开源表格引擎Univer:嵌入式协同、Canvas渲染与工程实践
2026/11/5 8:36:14
以下是关于Linux Socket 编程中sockaddr 数据结构族的深入解析(以 2026 年初主流 Linux 内核 6.6 ~ 6.14+ 版本为基准,基于 POSIX 标准和 glibc 2.38+ 实现)。sockaddr 族是 Socket API 的核心,用于表示网络地址、绑定端口和连接端点。它是抽象的地址结构,支持多种协议族(如 IPv4、IPv6、Unix Domain),确保 Socket 函数(如 bind、connect、accept)的通用性。
本文从基础概念、数据结构详解、代码示例、使用注意点到性能优化逐层展开。内容基于 Linux 内核源码(include/uapi/linux/socket.h 等)和 man pages 整理,适用于面试准备和实际开发。
struct sockaddr *类型参数,实现协议无关性。关键头文件:
#include<sys/socket.h>// sockaddr, sockaddr_storage#include<netinet/in.h>// sockaddr_in, sockaddr_in6#include<sys/un.h>// sockaddr_unsockaddr 族是一个“家族”,核心是struct sockaddr,其他结构通过类型转换兼容它。所有结构以sa_family开头,确保协议族区分。
structsockaddr{sa_family_tsa_family;// 地址族(如 AF_INET、AF_INET6、AF_UNIX)charsa_data[14];// 地址数据(协议特定,14 字节填充)};structsockaddr_in{sa_family_tsin_family;// AF_INETin_port_tsin_port;// 端口号(网络字节序,uint16_t)structin_addrsin_addr;// IPv4 地址unsignedcharsin_zero[8];// 填充字节(对齐到 16 字节)};structin_addr{in_addr_ts_addr;// IPv4 地址(uint32_t,网络字节序)};structsockaddr_inaddr;addr.sin_family=AF_INET;addr.sin_port=htons(8080);// 端口 8080inet_pton(AF_INET,"127.0.0.1",&addr.sin_addr);// IP 转换memset(addr.sin_zero,0,sizeof(addr.sin_zero));// 清零填充structsockaddr_in6{sa_family_tsin6_family;// AF_INET6in_port_tsin6_port;// 端口号(网络字节序)uint32_tsin6_flowinfo;// 流信息(通常 0)structin6_addrsin6_addr;// IPv6 地址uint32_tsin6_scope_id;// 接口索引(链路本地地址用)};structin6_addr{unsignedchars6_addr[16];// 128 位 IPv6 地址};structsockaddr_in6addr6;addr6.sin6_family=AF_INET6;addr6.sin6_port=htons(8080);inet_pton(AF_INET6,"::1",&addr6.sin6_addr);// 本地环回 IPv6addr6.sin6_scope_id=0;// 默认接口structsockaddr_un{sa_family_tsun_family;// AF_UNIX 或 AF_LOCALcharsun_path[108];// 路径名(NULL 终止字符串)};structsockaddr_unaddr_un;addr_un.sun_family=AF_UNIX;strncpy(addr_un.sun_path,"/tmp/mysock",sizeof(addr_un.sun_path)-1);// 路径名// 或抽象:addr_un.sun_path[0] = '\0'; strncpy(addr_un.sun_path + 1, "mysock", ...);structsockaddr_storage{sa_family_tss_family;// 地址族char__ss_padding[_SS_PADSIZE];// 填充(对齐到最大结构)__ss_aligntype __ss_align;// 对齐字段};structsockaddr_storageaddr_stor;socklen_taddr_len=sizeof(addr_stor);accept(sockfd,(structsockaddr*)&addr_stor,&addr_len);// 通用接收if(addr_stor.ss_family==AF_INET){/* 处理 IPv4 */}#include<sys/socket.h>#include<netinet/in.h>#include<unistd.h>#include<string.h>#include<stdio.h>intmain(){intsockfd=socket(AF_INET,SOCK_STREAM,0);// 创建 Socketif(sockfd<0){perror("socket");return1;}structsockaddr_inserv_addr;memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=INADDR_ANY;// 监听所有接口serv_addr.sin_port=htons(8080);if(bind(sockfd,(structsockaddr*)&serv_addr,sizeof(serv_addr))<0){perror("bind");close(sockfd);return1;}listen(sockfd,5);// 监听structsockaddr_storageclient_addr;socklen_taddr_len=sizeof(client_addr);intclientfd=accept(sockfd,(structsockaddr*)&client_addr,&addr_len);if(clientfd<0){perror("accept");close(sockfd);return1;}// 处理连接...close(clientfd);close(sockfd);return0;}(struct sockaddr *)转换具体结构,避免编译警告。sockaddr 族是 Socket 编程的基石,掌握它能让你写出高效、跨协议的网络代码。如果需要特定示例(如 UDP、多播、IPv6 迁移)或内核源码剖析,继续问~