sock_addr
/* Linux下定义在usr/include/bits/socket.h中 */
/* Structure describing a generic socket address. */
struct sockaddr
{
uint16_t sa_family; /* Comm data: address family and length. */
char sa_data[14]; /* Address data. */
};
在socket套接字编程中,sockaddr是一个通用的结构体,可以存储不同类型的地址结构。sa_family表示地址族,AF_INET表示IPv4,AF_INET6表示IPv6,sa_data包含套接字中的目标地址和端口信息。但是这个结构体通常只用来提供统一接口可以被bind()、connect()等函数调用,而不直接对结构体操作。
sockaddr_un
/* Linux下定义在usr/include/sys/un.h中 */
/* Structure describing the address of an AF_LOCAL (aka AF_UNIX) socket. */
struct sockaddr_un
{
uint16_t sun_family;
char sun_path[108]; /* Path name. */
};
sockaddr_un是一种UNIX套接字,通常在使用这种方式时不用网络套接字,而是用本地套接字,这种方式可以避免为黑客留下后门(据说~)。本地套接字与网络套接字的使用大体相同,主要区别在于使用socket()创建时,域参数只能选择PF_LOCAL和PF_UNIX,通讯类型只能选择SOCK_STREAM和SOCK_DGRAM,协议为默认协议;bind()绑定时填充的是sockaddr_un结构体,它的sun_family参数只能选择AF_LOCAL和AF_UNIX,sun_path参数为本地文件路径,通常放在/temp目录下。
sockaddr_in
/* Linux下定义在usr/include/netinet/in.h中 */
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
uint16_t sin_family;
uint16_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of 'struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
sizeof (uint16_t) -
sizeof (uint16_t) -
sizeof (struct in_addr)];
/* 其实就是unsigned char sin_zero[8]; */
};
sockaddr_in结构体是和sockaddr结构并列且等价的结构体,因此它们二者之间可以互相转化,也是真正用来提供给程序员进行填充操作的结构体,区别在于sockaddr_in将sa_data划分为sin_port和sin_addr,也就是把端口和IP地址信息区分开,sin_port采用了网络字节序,同时为了保持和sockaddr相同的字节大小,填充了8字节的sin_zero。这也是一个只针对IPv4地址的结构体,因此它的sin_family只能是AF_INET。
sockaddr_in6
/* Linux下跟sockaddr_in在同一个头文件 */
/* Ditto, for IPv6. */
struct sockaddr_in6
{
uint16_t sin6_family;
uint16_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};
sockaddr_in6也是一个专用的结构体,只针对IPv6,sin6_family参数只能选择AF_INET6,sin6_port也采用了网络字节序,sin6_flowinfo分为两个字段,低序的20位表示流标(flow label),高序的12位保留,对于具备范围的地址(scoped address),sin6_scope_id标识了其范围(scope)。
struct in_addr
/* Linux下与sockaddr_in在同一个头文件 */
/* Internet address. */
struct in_addr
{
uint32_t s_addr;
};
这个结构体在sockaddr_in中被使用来存储IP地址信息,因此它通常不单独使用,而是与sockaddr_in结合一起使用,它的结构比较简单,就是采用了4字节存储IP地址,不过也采用了网络字节序进行存储,使用时需要注意转换。
struct in6_addr
/* Linux下与sockaddr_in在同一个头文件 */
/* IPv6 address */
struct in6_addr
{
union
{
uint8_t __u6_addr8[16];
uint16_t __u6_addr16[8];
uint32_t __u6_addr32[4];
}__in6_u;
#define s6_addr __in6_u.__u6_addr8
#ifdef __USE_MISC
#define s6_addr16 __in6_u.__u6_addr16
#define s6_addr32 __in6_u.__u6_addr32
#endif
};
这个结构体也是与sockaddr_in6配合起来一起使用,通常不单独使用。它的结构比in_addr看起来稍微复杂,不过就是增加了一些预编译命令,它的主体是一个联合体,大小为16字节,因为IPv6地址长度是128位,刚好16字节,它使用联合体提供了几种不同的存储形式,为程序员提供了不同操作的可能。