1 Star 0 Fork 0

Shawy / 2023Linux

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
sockaddr.md 4.76 KB
一键复制 编辑 原始数据 按行查看 历史
Shawy 提交于 2023-04-29 19:46 . struct sockaddr

sockaddr 结构体

在介绍socket网络套接字的接口时,曾多次提到sockaddr结构体,它是一个==通用的==套接字地址结构,用于在套接字编程中传递不同协议族的地址信息。它的定义如下:

struct sockaddr {
sa_family_t sa_family; /* 地址族 */
char sa_data[14]; /* 地址数据 */
};
  • sa_family字段表示地址族(address family),用于指定地址的类型。常见的地址族有AF_INET(IPv4地址)、AF_INET6(IPv6地址)和AF_UNIX(Unix域地址)等。

  • sa_data字段表示协议地址,其长度和内容取决于地址族。例如,对于IPv4地址,它包含了IP地址和端口号;对于Unix域地址,它包含了文件系统中的路径名。

由于sockaddr结构并不能很好地表示各种类型的地址,因此通常会使用特定于地址族的结构来表示套接字地址,例如sockaddr_in(用于IPv4地址)和sockaddr_un(用于Unix域地址)。==这些结构与sockaddr结构具有相同的大小和对齐方式,可以相互转换。==

因此,这个结构体的唯一目的是为了将不同协议族的地址结构体指针转换为一个“通用”类型,以避免编译器警告。例如,对于IPv4协议族的地址结构体sockaddr_in,它的定义如下:

struct sockaddr_in {
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* 端口号 */
struct in_addr sin_addr; /* IPv4地址 */
};

这个结构体比sockaddr结构体更具体,它包含了IPv4协议族所需的地址信息。当我们调用套接字函数时,例如bind(2),我们需要将sockaddr_in结构体指针强制转换为sockaddr结构体指针,如下所示:

struct sockaddr_in addr;
/* 初始化addr */
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));

这样做是为了让套接字函数能够根据sa_family字段来判断实际的地址类型,并进行相应的处理。同样的道理,对于其他协议族,例如IPv6或UNIX域套接字,也有各自的地址结构体,例如sockaddr_in6和sockaddr_un,它们都可以转换为sockaddr结构体指针。

因此,我们可以认为sockaddr结构体是一个抽象的接口,它隐藏了不同协议族地址结构体之间的差异,让我们可以使用统一的方式来操作套接字。


image-20230429161434528

为了统一使用接口,Linux内核用结构体的前2个字节标定套接字的类型。即即套接字的类型。sa_family字段是一个sa_family_t类型(无符号整型)的变量,通常占用两个字节。

地址族用于指定地址的类型,它决定了套接字如何解释地址信息。常见的地址族有AF_INET(IPv4地址)、AF_INET6(IPv6地址)和AF_UNIX(Unix域地址)等。不同类型的套接字使用不同的协议来传输数据,因此需要使用不同的地址结构来表示它们的地址信息。

通过在sockaddr结构体中使用一个通用的字段来表示地址族,Linux内核可以统一处理不同类型的套接字地址,简化了套接字API的使用。在使用上的体现就是,不管是何种通信方式,网络还是本地通信,虽然在初始化套接字中的属性时使用的是struct sockaddr_instruct sockaddr_un,但是传参都统一类型转换为sockaddr*。这样就不用单独为不同的通信方式实现不同的接口了,从而减少了使用成本。


在多线程编程中,我们经常利用void*(它可以传递任意类型的数据)来给线程函数传递信息,为什么socket不使用void*来保存通信相关属性呢?

套接字API的设计可以追溯到20世纪70年代末,当时由贝尔实验室的研究人员开发了BSD Unix操作系统。在当时,C语言和Unix操作系统都处于起步阶段,许多现代编程语言和操作系统的特性还没有出现。

在设计套接字API时,研究人员希望能够提供一种通用的接口,用于支持不同类型的网络协议。为了实现这一目标,他们定义了一组通用的套接字地址结构,用于表示不同类型的网络地址。这些结构体包含了特定的字段,用于存储地址族、协议地址等信息。

虽然使用void*指针也可以实现类似的功能,但是这样做会使得代码变得更加复杂和难以维护。程序员需要手动管理内存,并且需要使用类型转换来访问指针指向的数据。相比之下,使用特定的结构体类型来表示套接字地址更加简单、直观和安全。

因此,套接字API最终采用了特定的结构体类型来表示套接字地址,而不是使用void*指针。这一设计决策为套接字API提供了清晰、简洁和易用的接口,并且在后来被广泛采纳。

C++
1
https://gitee.com/shawyxy/2023-linux.git
git@gitee.com:shawyxy/2023-linux.git
shawyxy
2023-linux
2023Linux
3550a916d5ad03043c597f80d5cf4cd8f861e3ce

搜索帮助