2.套接口地址结构
文章接前面的例子程序。首先介绍套接口地址结构:
struct sockaddr_in,定义在netinet/in.h中,一般是在/usr/include 下
?
struct in_addr {
?? in_addr_t s_addr;/*32字节的ipv4地址*/
}
?
struct sockaddr_in {
?? uint8_t sin_len;
?? sa_family_y sin_family;
?? in_port_t sin_port;
?
?? struct in_addr sin_addr;
?? char sin_zero[8];
}
?
?
POSIX.1g只需要3个成员sin_family,sin_addr,sin_port。定义额外成员可以接受,所以可以理解sin_zero是个缓冲,所有套接口大小都是16字节。
sin_len表示长度成员(因为后面有个sin_zero扩展位,虽然没有使用,我是这么猜的)。
sin_family表示地址族成员。
明显了sin_addr是32位IP地址。
?? 所以前面的程序中inet_pton(AF_INET, argv[1], &servaddr.sin_addr)将参数1放入地址
sin_port则是无符号的16位,既是端口号。
?? servaddr.sin_port = htons(atoi(argv[2]));既为放入端口号。
?
sin_zero成员暂不适用,一般置成0,但是一般我们在初始化时候将整个数据结构置成0,既bzero(&servaddr, sizeof(servaddr));
?
结构仅给定主机上使用,虽然成员在不同主机间通信,但结构本身不参与通信。
?
?
通用套接口地址结构
?? 前面问题是IPV4的套接口,但在传递函数直接时候,必须使用通用套接口,原本ANSIC可以使用void *来解决,但是套接口是在ANSIC之前定义,因此出现了通用套接口
?
struct sock_addr {
?? uint8_t sa_len;
?? sa_family_t sa_family;
?? char sa_data[14];
}
这就是为什么在bind(listenfd, (struct socket_addr *)&servaddr, sizeof(servaddr));要强制转换。
?
IPV6套接口地址结构就省略了。
?
关于htons和htonl函数,字节排序函数,主机排序可能有2种,一种是小段字节序:低序字节存储在起始位置,相反则是大端字节序。网络协议中有网络字节序,这2个函数则是将字节序变成网络字节序。