网络字节序:
我们应该已经知晓,内存中的多字节数据相对于内存地址有大端和小端之分,
磁盘文件中的多字节数据相对于文件内部的偏移地址也有大端和小端之分。
同样,网络数据流同样也有大端小端之分。例如:发送端主机通常将发送缓冲
区中的数据按内存地址从低到高的顺序发出,接受端主机把从网络上接受到的
数据存储在接受缓冲区中,也是按内存地址从低到高的顺序保存,所以,网络
数据的地址应该是:先发出的数据是低地址,后发出的数据是高地址。
TCP/IP协议规定,网络数据流应该采用大端字节序,即低地址高字节。
字节序
大端字节序(Big Endian):
最高有效位(MSB:Most Significant Bit)存储于最低内存地址处,最低有效位(LSB:Lowest Significant Bit)存储于最高内存地址处。
小端字节序(Little Endian)
最高有效位(MSB:Most Significant Bit)存储于最高内存地址 处,最低有效位(LSB:Lowest Significant Bit)存储于最低内存地址处。
主机字节序
不同的主机有不同的字节序,如x86为小端字节序,Motorola 6800为大端字节序,ARM字节序是可配置的。
网络字节序
网络字节序规定为大端字节序
例如:现在两台主机要通过网络进行通信,地址0-1是16位的源端口号,假如这个端
口是1000(0x3e8),则0地址存0x03,地址1是0x03,那就是先发0x03再发0x06,这16位
在发送主机缓冲区中也应该是地址0x03,高地址存0xe8。但是,如果发送主机是小端字
节序,这16位被解释成0xe803,而不是1000.因此发送主机把1000填到发送缓冲区之前要
做字节序转换。同样的,接受端主机如果是小端字节序,接到16位的源端口号也要做字节序
转换如果主机是大端字节序的,发送和接受都不需要做转换。同理,32位的IP地址也需要考虑
网络字节序和主机字节序的问题。
所以,开发者们设计了网络字节序转换的库函数,用来进行网络字节序和主机字节序的转换。
#include
uint32_t htonl(uint32_t hostlog);
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位短整数。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,
这些函数不做转换,将参数原封不动的返回。
事例:
server_address.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY表示可以到达服务器任一网络接口的链接
server_addresss.sin_port=htons(9372);
printf("port=%d\n",ntohs(clientaddr.sin_port));