1. 地址类API
1.1 字节序
分为大端字节序和小端字节序,区别是大端字节序更符合人类的视觉,即高位字节存储在低位地址处,低位字节存储在高位字节处,而小端序符合计算机的口味,即高位字节存储在高位地址处,低位字节存储在低位地址处。
一般PC使用小端字节序,所以小端字节序也称为主机字节序;网络数据传送使用大端字节序,所以大端字节序也称为网络字节序。
一个简单的判断程序:
void byteorder()
{
union byteorder {
short value;
char union_byte[sizeof(short)];
} test;
test.value = 0x0102;
if ((test.union_byte[0] == 1) && (test.union_byte[1] == 2))
printf("Big endian\n");
else if ((test.union_byte[0] == 2) && (test.union_byte[1] == 1))
printf("Little endian\n");
else
printf("Unknown\n");
}
1.2 通用Socket地址
#include <bits/socket.h>
struct sockaddr
{
sa_family_t sa_family; // 地址族类型,通常与协议族类型对应,
char sa_data[14]; // Family-specific address info, 存放socket地址
};
常见的协议族(protocol family,也称domain)
协议族 | 地址族 | 描述 |
---|---|---|
PF_UNIX | AF_UNIX | UNIX 本地域协议族 |
PF_INET | AF_INET | TCP/IPv4 协议族 |
PF_INET6 | AF_INET6 | TCP/IPv6 协议族 |
AF_*与PF_*的宏都定义在bits/socket.h
中,两者值相同,所以可以混用。
协议族及其地址值
协议族 | 地址值含义和长度 |
---|---|
PF_UNIX | 文件的路径名,长度可达108bytes |
PF_INET | 16 bits 端口号和 32 bits IPv4 地址,共6字节 |
PF_INET6 | 16 bits 端口号,32 bits 流标识,128 bits IPv6 地址,32 bits范围 ID,共26 字节 |
由上,sockaddr 放不下多数协议族地址,而设计了下面的sockaddr_storage。
#include <bits/socket.h>
struct sockaddr_storage
{
sa_famiy_t sa_family;
unsigned long int __ss_align;
char __ss_padding[128 - sizeof __ss_align];
};
不仅提供了足够大的空间用于存放地址,而且是内对齐的。
但是因为函数都传递struct sockaddr*
类型参数,所以都需要进行强制类型转换,而使用domain
判断具体是使用的哪一个。
1.3 专用socket地址
1.3.1 UNIX 本地域协议族
#include <sys/un.h>
struct sockaddr_un
{
sa_family_t sin_family; // 地址族:AF_UNIX
char sun_path[108]; // 文件路径名
};
1.3.2 IPv4
struct sockaddr_in
{
sa_family_t sin_family; // 地址族:AF_INET
u_int16_t sin_port; // 端口号,要用网络字节序表示
struct in_addr sin_addr; // IPv4地址结构体
};
struct in_addr
{
u_int32_t s_addr; // IPv4 地址,要用网络字节序表示
};
1.3.3 IPv6
struct sockaddr_in6
{
sa_family_t sin6_family; // 地址族:AF_INET6
u_int16_t sin6_port; // 端口号,要用网络字节序表示
u_int32_t sin6_flowinfo; // 流信息,应设置为0
struct in6_addr sin6_addr; // IPv6 地址结构体
u_int32_t sin6_scope_id; // socpe ID, 尚处于实验阶段
};
struct in6_addr
{
unsigned char sa_addr[16]; // IPv6 地址,要用网络字节序表示
}