uint16_t value = 0xabcd;
uchar ch[2];
memcpy(ch,&value,sizeof(uint16_t);
ch[0] = 0xab
ch[1] = 0xcd;
ch[0] = 0xcd;
ch[1] = 0xab;
htons:是主机字节序转成网络字节序;
ntohs:是网络字节序转成主机字节序;
网络字节序是大端法排序
主机字节序,则会根据CPU、操作系统的不同而不同,可能是大端排序,也可能是小端排序
倘若,通信的两端环境完全相同,通信过程中,可以不必进行字节序转换;
但是,如果通信两端环境不同,则必须要先统一字节序,
即:
socket send端,将该主机的uint16_t,uint32_t类型数据分别使用htons,htonl转成大端排序(如果主机实际是大端,调用函数,实际上没操作,如果是小端,就给转成大端);
uint16_t send_value = 0xabcd;
htons(value);
保证如上例中,使报文数据流是先存 0xab,后存0xcd
socket recv端,收到的uint16_t,uint32_t类型的数据分别使用 ntohs,ntohl转成该主机对应的字节序形式(如果主机是大端,调用函数也不会转换,结果为0xabcd,如果主机是小端,使用该函数会将数据转换为小端顺序(将0xab和0xcd的顺序调换,从而保证跟send端的数据保持一致)。
uchar ch[2]={0xab,0xcd};
uint16_t recv_value = *(uint16_t*)ch;
如果主机是大端序,则recv_value值为0xabcd; //与发送端的0xabcd匹配
如果主机是小端序,则recv_value值为0xcdab; //与发送端的0xabcd,不匹配
故需要使用ntohs函数,转换成小端序,
//报文数据
uchar ch[2]={0xab,0xcd};
uint16_t recv_value = *(uint16_t*)ch; //值为 0xabcd 或者 0xcdab
recv_value = ntohs(recv_value); //值为 0xabcd
除了使用:uint16_t recv_value = *(uint16_t*)ch; 方式外,
可以使用mecpy(&recv_value,ch,sizeof(uint16_t));
小结:
使用ntohs能够保证 收到的数据跟 报文中的数据字节顺序完全一致。如上,报文中数据顺序是0xab,0xcd,使用ntohs后,
收到的一定是0xabcd.
使用htons能够保证报文中的数据字节顺序跟要发送的数据字节顺序完全一致。如上,要传的数据是0xabcd,使用htons后,报文中的一定是0xabcd.
故send,recv两边为了移植方便,两边对于uint16_t 数据都要分别添加 htons 和 ntohs;
对于uint32_t数据两边分别添加 htonl 和 ntohl
htons函数是固定的, 相当于将不同字节序的主机的字节序都统一成 网络字节序(大端序)
ntohs函数则是根据主机的不同,将网络字节序转换成对应主机的字节序,从而保证 send,recv 两端发送和收到的数据时一致的。
因为int型数据,一个数据占多个字节,所以会产生字节序的问题,故需要调用htons,ntohs进行统一。
当数据时字符串数组,此时,报文数据就是一个字节,一个字节的存放,不存在字节的问题,也不需要调用htons,ntohs进行转换。
参考:https://blog.csdn.net/zouxinfox/article/details/1814088