地址族与数据序列
本章主要讲解为 socket 分配 IP 地址和端口号。
# 3.1 分配给套接字的 IP 地址与端口号
# 3.1.1 IP
网络地址(Internet Address)分为 IPv4 和 IPv6。
将数据包发给一个网络主机时,需要先传给这个主机所在子网的路由器或交换机。
# 3.1.2 端口号
端口号用于区分将数据传输给哪个具体的应用程序。
计算机一般有 NIC(网络接口卡)数据传输设备,通过 NIC 接收的数据内有端口号,操作系统参考端口号把信息传给相应的应用程序。
虽然端口号不能重复,但是 TCP 套接字和 UDP 套接字不会共用端接口号,所以允许重复。如果某 TCP 套接字使用了 9190 端口号,其他 TCP 套接字就无法使用该端口号,但是 UDP 套接字可以使用。
总之,数据传输目标地址同时包含IP地址和端口号,只有这样,数据才会被传输到最终的目的应用程序。
# 3.2 地址信息的表示
# 3.2.1 表示 IPv4 地址的结构体
使用 struct sockaddr_in
来表示 IPv4 的结构体:
struct sockaddr_in
{
sa_family_t sin_family; //地址族(Address Family)
uint16_t sin_port; //16 位 TCP/UDP 端口号
struct in_addr sin_addr; //32位 IP 地址
char sin_zero[8]; //不使用
};
2
3
4
5
6
7
8
其中的 struct in_addr
用来存放 32 位 IP 地址:
struct in_addr
{
in_addr_t s_addr; //32位IPV4地址
}
2
3
4
下面逐个分析一下 struct sockaddr_in
的各个成员。
# 1)sin_family
每种协议族适用的地址族均不同。比如,IPV4 使用 4 字节的地址族,IPV6 使用 16 字节的地址族。
地址族(Address Family) | 含义 |
---|---|
AF_INET | IPV4用的地址族 |
AF_INET6 | IPV6用的地址族 |
AF_LOCAL | 本地通信中采用的 Unix 协议的地址族 |
# 2)sin_port
16 位端口号,以网络字节序保存。
# 3)sin_addr
32 位 IP 地址信息,以网络字节序保存
# 4)sin_zero
无特殊含义,必须填充为 0
# 3.2.2 sockaddr_in 结构体的使用
我们需要使用 bind 函数来将 socket 与地址信息进行绑定,但 bind 函数其实想要接收的地址信息类型是 struct sockaddr *
:
struct sockaddr
{
sa_family_t sa_family; // 地址族信息
char sa_data[14]; // 地址信息
}
2
3
4
5
这个 struct 在 char[14]
中保存端口号、IP 等信息,对于程序来说不太好填充,所以我们使用更方便的 struct sockaddr_in
来填充,然后将其转化为 struct sockaddr *
传给 bind。
所以一般使用方法是:
struct sockaddr_in serv_addr;
...
int is_bind = bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
...
2
3
4
即:先声明一个 sockaddr_in 的实例,然后将其指针转为 (struct sockaddr *)