socket通信交互流程
网络字节序
一、网络字节序
- 在计算机世界里,有两种字节序:
- 大端字节序: 低地址高字节,高地址低字节
- 小端字节序: 低地址低字节,高地址高字节
- 例如:1001(十进制)用16进制表示为0x03e9.,两个字节表示
- 网络端口号,就是用16位,两字节来表示;
1. 如何定义网络数据流的地址呢?
- 内存中的多字节数据相对于内存地址有大端和小端之分|(内存地址是没有什么大端小端的,理解好大端小端是对数据来说的)
- 磁盘文件中的多字节数据相对于文件中偏移地址也有大端小端之分
- 网络数据流同样有大端小端之分
- 在网络上,发送数据的时候,发送主机通常将缓冲区中的数据按内存地址从低到高的顺序发出;
- 而接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;(先接收到的先放在低地址上)
- 因此,网络数据流的地址应该这样规定:先发出的数据是低地址,后发出的数据是高地址;(无论是什么大端或小端字节序)
- 那么如果客户端是小端而服务器端是大端这就有问题了!
- 所以要统一标准,否则数据无法交互
- 所以,TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节(无论是服务器端发送给客户端还是客户端发送给服务器端);
- 大到大,小到小不用转换;大到小,小到大要转换
- 32位的IP地址也要考虑网络字节序和主机字节序的问题
2. 怎么使网络程序具有可移植性?
为了使网络程序具有可移植性,使同样的C代码在大端和小端的计算机上编译后都能正常运行,可以调用以下库函数做网络字节序(大端字节序)和主机字节序(有的大端和大部分小端)的转换
// - 这些库函数会检查主机的字节序是大端还是小端(若已经是大端字节序就不会转换了因为网络字节序是大端字节序)
#include <arpa/inet.h>
h: host | n: network | l: long (32位长整数)| s: short (16位 短整型)
// 主机转网络的
uint32_t htonl(unit32_t hostlong); //把主机字节序转换成网络
uint16_t htons(unit16_t hostshort);
// 接下来是网络转主机的
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
在前面写贴上标签的代码的时候:主机字节序转换成网络字节序
- IP地址和端口号在写到标签上时要写一下转换的函数
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//监听本机所有的IP地址
- server_addr.sin_port = htons(SERVER_PORT);//绑定端口号
- inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);//将字符串类型的IP地址,转换成网络字节序的整数类型的IP
-
总结:
- 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动的返回;