《unix网络编程》第三章笔记
每个协议族都定义了自己的套接字地址结构。这些结构体的名字均以sockaddr_开头,并以对应每个协议族的唯一后缀结尾。
IPV4套接字地址结构,以sockaddr_in命名,定义在<netinet/in.h>头文件中
struct in_addr {
in_addr_t s_addr;// uint32_t IPV4 address, network byte ordered
}
struct sockaddr_in {
uint8_t sin_len; // length of structure(16)
sa_family_t sin_family; // AF_INET
in_port_t sin_port; // uint16_t TCP or udp port number, network byte ordered
struct in_addr sin_addr; // 32bit IPV4 address, network byte ordered
char sin_zero[8];// unused
}
每当一个套接字函数需要一个指向某个套接字地址结构的时候,都需要将这个指针强制类型转换成一个通用套接字结构的指针。通用套接字结构如下:
struct sockaddr {
uint8_t sa_len;
sa_family_t sin_family; // AF_INET
char sa_data[14];// protocol address
}
注意到上面结构体中的端口号和地址需要以网络字节序存储。所谓网络字节序就是大端存储。
书中定义大小端是这么描述的:术语小端和大端表示多个字节值的哪一段(小端或大端)存储在该值的起始地址。
把某个系统所用的字节序称为主机子节序,可能是大端,也可能是小端。判断主机字节序程序:
<span style="font-size:18px;">int main(void)
{
union {
short s;
char c[sizeof(short)];
}un;
un.s = 0x0102;
if (sizeof(short) == 2)
{
if (un.c[0] == 1 && un.c[1] == 2)
{
printf("big-endian\n");
}
else if (un.c[0] == 2 && un.c[1] == 1)
{
printf("little-endian\n");
}
else
{
printf("unknow\n");
}
}
else
{
printf("sizeof(short) == %d\n", sizeof(short));
}
return 0;
}</span>
两个系统间进行网络通讯是以大端方式发送,如主机序是小端的,需要转换成大端存储再进行发送。两种字节序之间的转化函数:
#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
h代表host,n代表network,s代表short,l代表long。即使在64位主机上,s和l仍旧表示16位和32位的值。