乐闻世界logo
搜索文章和话题

C 套接字 sockaddr 和 sockaddr_storage 背后的原理

5 个月前提问
4 个月前修改
浏览次数25

1个答案

1

介绍 C 套接字中的 sockaddr 和 sockaddr_storage 结构体

sockaddr 结构体

在 C 语言的网络编程中,sockaddr 结构体用于存储地址信息。它是一种通用的地址结构体,用于处理各种类型的地址。最初设计sockaddr是为了能够处理多种不同的协议地址。

c
struct sockaddr { sa_family_t sa_family; // 地址族 char sa_data[14]; // 包含目标地址和端口信息 };

地址族(sa_family) 标识了地址类型,比如 AF_INET 用于IPv4地址,AF_INET6 用于IPv6地址等。这个字段很重要,因为它帮助程序解析后面的 sa_data 数据。

然而,sockaddr 结构体的一个限制是它的大小固定,而且设计上没有考虑到地址长度超过其提供的存储空间的情况。因此,在处理IPv6这样需要更多空间存储地址的协议时,这种结构体就显得不够用。

sockaddr_storage 结构体

为了解决 sockaddr 的这些限制问题,引入了 sockaddr_storage 结构体。这个结构体足够大,能够容纳支持的所有协议的地址,保证了与将来的协议兼容。

c
struct sockaddr_storage { sa_family_t ss_family; // 地址族 char __ss_pad1[_SS_PAD1SIZE]; int64_t __ss_align; // 保证结构体在任何平台上都对齐 char __ss_pad2[_SS_PAD2SIZE]; };

sockaddr_storage 的设计主要确保了两点:

  1. 足够的空间: 提供了足够的空间以适配不同的地址类型,如IPv6。
  2. 适当的对齐: 通过 __ss_align 确保了结构体在不同平台上能够正确地对齐。

使用实例

假设您正在编写一个服务器应用程序,需要接受来自IPv4和IPv6地址的客户端连接。在这种情况下,使用 sockaddr_storage 结构体来存储客户端的地址信息是一个理想的选择。

c
#include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> void process_connection(int client_socket, struct sockaddr_storage client_address) { char host[NI_MAXHOST]; char service[NI_MAXSERV]; getnameinfo((struct sockaddr *)&client_address, sizeof(client_address), host, NI_MAXHOST, service, NI_MAXSERV, 0); printf("Connected with %s:%s\n", host, service); } int main() { int server_socket; struct sockaddr_storage client_address; socklen_t client_address_len = sizeof(client_address); // Setup socket and bind (省略具体代码细节) listen(server_socket, 5); while (1) { int client_socket = accept(server_socket, (struct sockaddr *) &client_address, &client_address_len); if (client_socket == -1) { perror("accept"); continue; } process_connection(client_socket, client_address); close(client_socket); } }

在这个例子中,通过使用 sockaddr_storage 结构体,我们能够无缝地处理来自IPv4和IPv6的连接,而无需担心地址空间的问题。这种方式增强了程序的兼容性与未来的扩展性。

2024年6月29日 12:07 回复

你的答案