2023.7.10
第3章、地址族与数据序列
3.1 分配给套接字的IP地址与端口号
IP 是 Internet Protocol(网络协议)的简写,是为收发网络数据而分配给计算机的值。端口号并非赋予计算机的值,而是为了区分程序中创建的套接字而分配给套接字的序号。
为使计算机连接到网络并收发数据,必须为其分配 IP 地址。IP 地址分为两类。
- IPV4(Internet Protocol version 4)4 字节地址族
- IPV6(Internet Protocol version 6)6 字节地址族
两者之间的主要差别是 IP 地址所用的字节数,目前通用的是 IPV4 , IPV6 的普及还需要时间。
IP地址用于区分计算机,只要有IP地址就能向目标主机传输数据,但是只有这些还不够,我们需要把信息传输给具体的应用程序。 端口号就是在同一操作系统内为区分不同套接字而设置的。 端口号由 16 位构成,可分配的端口号范围是 0~65535 。但是 0~1023 是知名端口,一般分配给特定的应用程序,所以应当分配给此范围之外的值。 虽然端口号不能重复,但是 TCP 套接字和 UDP 套接字不会共用端接口号,所以允许重复。 总之,数据传输目标地址同时包含IP地址和端口号,只有这样,数据才会被传输到最终的目的应用程序。
3.2 地址信息的表示
表示 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]; //不使用
};
该结构体中提到的另一个结构体 in_addr 定义如下,它用来存放 32 位IP地址:
struct in_addr
{
in_addr_t s_addr; //32位IPV4地址
}
结构体 sockaddr_in 的成员分析:
- 成员 sin_family:每种协议适用的地址族不同,比如,IPV4 使用 4 字节的地址族,IPV6 使用 16 字节的地址族。
- 该成员保存 16 位端口号,重点在于,它以网络字节序保存。
- 该成员保存 32 为IP地址信息,且也以网络字节序保存。
- 无特殊含义。只是为结构体 sockaddr_in 结构体变量地址值将以如下方式传递给 bind 函数。
3.3 网络字节序与地址转换
不同的 CPU 中,4 字节整数值1在内存空间保存方式是不同的。
有些 CPU 这样保存:
00000000 00000000 00000000 00000001
有些 CPU 这样保存:
00000001 00000000 00000000 00000000
两种一种是顺序保存,一种是倒序保存 。若不考虑顺序就收发数据容易出问题。
CPU 保存数据的方式有两种,这意味着 CPU 解析数据的方式也有 2 种:
- 大端序(Big Endian):高位字节存放到低位地址
- 小端序(Little Endian):高位字节存放到高位地址
在通过网络传输数据时必须约定统一的方式,这种约定被称为网络字节序,非常简单,统一为大端序。即,先把数据数组转化成大端序格式再进行网络传输。
介绍一下帮助转换字节序的函数:
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
例如:htons(host to network short):把short型数据从主机字节序转换为网络字节序。
通常,以s作为后缀的函数中,s代表2字节的short,因此用于端口号转换;以l作为后缀的函数中,l代表4个字节,因此用于IP地址转换。
实验:
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
unsigned short host_port = 0x1234;//保存2个字节的数据
unsigned short net_port;
unsigned long host_addr = 0x12345678;//保存4个字节的数据
unsigned long net_addr;
//转换为网络字节序
net_port = htons(host_port);
net_addr = htonl(host_addr);
printf("Host ordered port: %#x \n", host_port);
printf("Network ordered port: %#x \n", net_port);
printf("Host ordered address: %#lx \n", host_addr);
printf("Network ordered address: %#lx \n", net_addr);
return 0;
}
实验结果:
这是在小端 CPU 的运行结果。大部分人会得到相同的结果,因为 Intel 和 AMD 的 CPU 都是小端序为标准。