最近在看UNPV13E,这本书是基于unix系统的,头文件的目录和结构体定义跟linux系统不尽相同,但是这两个系统中C代码描述的TCP/IP协议内容最终含义都是差不多的。
所以这里就使用linux系统的定义来描述了,如果想研究unix系统,可以去查4.4BSD-LITE 相关代码。
1. 通用套接字地址结构:sockaddr
定义在 include/linux/socket.h 中:
typedef unsigned short sa_family_t;
/*
* 1003.1g requires sa_family_t and that sa_data is char.
*/
struct sockaddr {
sa_family_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
2. IPV4 套接字地址结构:sockaddr_in
定义在include/linux/in.h 中:
/* Structure describing an Internet (IP) socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {
sa_family_t sin_family; /* Address family */
__be16 sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
#define sin_zero __pad /* for BSD UNIX comp. -FvK */
sin_family: 是协议族的意思. sa_family_t 是个16位无符号整数,定义如下:
typedef unsigned short sa_family_t;
ipv4 中 sin_family = AF_INET.
sin_port: 是端口号。 是一个16位无符号整数。
sin_addr: 是网络地址。 是个in_addr 结构体,定义如下:
/* Internet address. */
struct in_addr {
__be32 s_addr;
};
这里为啥要设计成一个结构体,而不直接一个32位无符号整数呢?这是有故事的~
早期版本把in_addr 结构定义为多种结构的联合(union),以便于访问32位IPV4地址中的所有4个字节,这样用在地址划分为A,B,C三类的时期,非常方便获取地址中的某个字节。然而随着子网划分技术出现,和无数地址编排函数的出现,各种地址类正在消失,这个联合也就不需要了。所以现在定义为一个32位的结构体了。
sin_zero: 未使用字段,用来做pad,字节对齐作用。再填写套接字地址结构的时候,总是应该把整个套接字地址结构置为0,而不单单把sin_zero字段置为0。
3. IPV6 套接字地址结构:sockaddr_in6
定义在 include/linux/in6.h 中
struct sockaddr_in6 {
unsigned short int sin6_family; /* AF_INET6 */
__be16 sin6_port; /* Transport layer port # */
__be32 sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
__u32 sin6_scope_id; /* scope id (new in RFC2553) */
};