1.最常用的大小端转换函数
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
h表示host,指小端,n表示network指大端,l表示32位长整数,s表示16位短整数。
注意:32位是用来转换IP地址的,16位是用来转换端口号的
使用平台:linux和windows
2.linux专门的转换函数
64字节主机转网络:htobe64(uint64_t data)
64字节网络转主机:be64toh(uint64_t data)
32字节主机转网络:htobe32(uint32_t data)
32字节网络转主机:be32toh(uint32_t data)
16字节主机转网络:htobe16(uint16_t data)
16字节网络转主机:be16toh(uint16_t data)
使用平台:linux
3.封装好的函数可以实现域名解析,大小端转换以及点分十进制和字符串之间的转换
int getaddrinfo(const char *hostname,
const char *service,
const struct addrinfo *hints,
struct addrinfo **result );
通俗一点理解就是给了域名或者IP地址,以及端口号,可以自动生成socket结构体。
hostname:主机名(域名)或者地址串(IPv4的点分十进制或者IPv6的十六进制)
service:服务名或者端口号
hints:对返回值的限制要求结构体,其中包括了socket函数会用到的family,type,protocol,也有sockaddr_in结构体中需要的sin_family。
具体结构如图所示:
struct addrinfo {
int ai_flags;
int ai_family;//socket的第一个参数
int ai_socktype;//socket的第二个参数
int ai_protocol;//socket的第三个参数
socklen_t ai_addrlen;//connect和bind的第三个参数
struct sockaddr *ai_addr;//connect和bind的第二个参数
char *ai_canonname;
struct addrinfo *ai_next;
};
result:就是一个指向addrinfo的链表可以使用每一个addrinfo中的信息去创建套接字和绑定监听
注意:hints和result是同一个结构体,但是hints是输入参数,需要填充比如family,flags,socktype等信息,而result会根据hints中的信息,得到对应的套接字函数需要的信息和结构体,这过程中就封装了很多套接字函数初始化的步骤,而大小端转换也在其中。
想要通过套接字地址结构获取IP地址,可以使用getnameinfo函数,刚好和 getaddrinfo是相反的。
int getnameinfo(const struct sockaddr *sockaddr,
socklen_t addrlen,
char *host,
size_t hostlen,
char *serv,
size_t servlen,
int flags);
sockaddr:指向包含协议地址的套接口地址结构
addrlen:sockaddr结构的长度
host:输出参数,对应的IP地址
hostlen:所允许的最大输出字符长度
具体详见CSAPP第11章的tiny server和udp的第11章第6小节
其他注意事项:
字节序转换只有在端口和IP地址处用到,但是后面的数据传输过程当中,并没有使用到。
个人理解为:端口和IP地址是16位或者32为多字节数据,需要大小端转换,但是在数据传输过程中,都是以字符串的形式传输的,字符串中每个字符只有8位,也就是一个字节,无论在大端还是小端,结果都是一样的(这需要对大小端概念有一个比较清晰的理解) |