在Socket编程中,inet_ntop、inet_pton 以及字节序转换函数(如 htons(), htonl(), ntohs(), ntohl())是非常重要的工具,用于处理IP地址和端口号的表示与转换 htonl(): 这个函数用于将无符号长整型(可能是IPv4地址或其他数据)从主机字节序转换为网络字节序。 ntohl(): 这个函数与 htonl() 相反,用于将无符号长整型从网络字节序转换为主机字节序。
在对IP地址结构体SOCKADDR_IN赋值的时候,经常会用到下列的函数htonl,htons,inet_addr,与之相对应的函数是ntohl,ntohs,inet_ntoa。 16777343 (网络字节序) 然后解析上面提到的函数作用就简单多了,看以下代码: SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=htonl 函数的作用是把一个主机字节序转换为网络字节序,也就是上面转换过程中第二步转换为第三步的作用,127.0.0.1的主机字节序是2130706433,把主机字节序2130706433转换为网络字节序就是htonl addrSrv.sin_addr.S_un.S_addr=htonl(2130706433);这句还可以写为: addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1 与htonl,htons,inet_addr,与之相对应的函数是ntohl,ntohs,inet_ntoa,不难看出,ntohl,ntohs,inet_ntoa,这三个函数其实就是执行与他们相对应函数的相反转换
BSD socket提供了一系列函数来完成这个任务,其中最常用的是htons和htonl。 htons函数的作用是将16位的主机字节序转换为网络字节序。 htonl函数的作用与htons类似,但是针对的是32位的主机字节序。 uint16_t htons(uint16_t hostshort); uint32_t htonl(uint32_t hostlong); 除了htons和htonl之外,还有ntohs、ntohl等函数 ,它们的作用与htons和htonl相反,用于将网络字节序转换为主机字节序。 serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); // 将主机字节序转换为网络字节序 serv_addr.sin_addr.s_addr = htonl
型的整数,那么假设其二进制小端模式表示为11111111111111110000000000000000那么其大端模式表示为00000000000000001111111111111111,利用c语言的htonl 举个例子: 在C语言端发送一个int32_t数据过程如下: 发送端(c语言) char buf[100]; int32_t x = 100; ((int*)buf)[0] = htonl bytes.NewReader(buffer) err = binary.Read(buf, binary.BigEndian, &num) 注意:这里golang并没有类似ntohl()、htonl
Linux提供了如下的四个函数来完成主机字节序和网络字节序之间的转换: #include <netinet/in.h> unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int htonl(unsigned long int netlong); unsigned short int htonl(unsigned short int netshort); 长整型函数常用来转换IP地址, 短整形常用来转换端口号
#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); //把uint32_t类型从主机序转换到网络序 uint16_t htons long val) { if(__BYTE_ORDER == __LITTLE_ENDIAN) { return (((unsigned long long )htonl ((int)((val << 32) >> 32))) << 32) | (unsigned int)htonl((int)(val >> 32)); } else if (__ (box_in.st64.u32_l); box_out.st64.u32_l = htonl(box_in.st64.u32_h); return box_out.u64 (x) #define htonll(x) __bswap_64 (x) #endif #endif #endif ---- 参考资料 [1]网络字节序与主机字节序 高低位 [2]htonl
而针对不同的机器,有着不同的模式,有些是大端,有些是小端,如果在网络传输中发送的是原数据0x3456,而不是0x5634,那么会发生灾难性的错误,因此需要在发送前调用htons或者htonl函数将其转换为大端模式 =============== 32位小端--->大端:78563412 78 56 34 12 4.调用函数 在C/C++网络开发中可以通过引入 #include <netinet/in.h> 调用htonl 那么下面来使用一下,使用之前先阐述一下这几个函数: htonl() 32位无符号整型的主机字节顺序到网络字节顺序的转换(小端->大端) htons() 16位无符号短整型的主机字节顺序到网络字节顺序的转换 htons ntohl ntohs函数调用=========="<<endl; printf("16位小端--->大端:%x\n",htons(a)); printf("32位小端--->大端:%x\n",htonl (b)); 输出结果: ==========htonl htons ntohl ntohs函数调用========== 16位小端--->大端:3412 32位小端--->大端:78563412
下面是一些字节序转换函数: # include < arpa/inet.h > uint32_t htonl(uint32_t hostlong); uint16_t htons( uint32_t netlong); uint16_t ntohs(uint16_t netshort); 说明:h代表host;n代表network;s代表short;l代表long 描述: htonl ntohl()函数功能与 htonl()函数相反 ntohs()函数功能与htons()函数相反 我们可以进行验证,刚才已经通过程序测试出我的主机是小端字节序,接下来使用函数 htonl()将整数0x12345678 unsigned char*)&x; printf("转换前:%0x,%0x,%0x,%0x\n",p[0],p[1],p[2],p[3]); unsigned int y = htonl unsigned long addr = inet_addr("192.168.0.100");//将点分十进制转换为32bit地址 printf("addr = %u\n",htonl
但是我有个问题,我们知道转化成网络字节序可以使用接口htonl,但是我们之前写socket服务端的时候,端口号也需要转化为网络字节序,可是确实直接将变量作为实参传递,这不是没有进行序列化也可以吗? 与序列化的配合 发送方序列化二进制数据时,对每个多字节整数调用htonl()/htons()转大端; 接收方用ntohl()/ntohs()转回本地字节序。 三、htonl 与序列化的本质区别:简单数据 vs 结构化数据 1. 写入age(转大端) uint32_t net_age = htonl(u->age); memcpy(buf+4+name_len, &net_age, 4); 技术手段:通过htonl转网络字节序,或文本序列化规避端序。 2. 结构化标识(字段解析规则) 处理对象:结构体、对象等复杂数据结构。
= 48) { fprintf(stderr,"size error\n"); return; } memset((char*)data, 0, sizeof(data)); data[0] = htonl ) | (VN << 27) | (MODE << 24) | (STRATUM << 16) | (POLL << 8) | (PREC & 0xff));//构造协议头部信息 data[1] = htonl (1<<16); data[2] = htonl(1<<16); gettimeofday(&now, NULL); data[10] = htonl(now.tv_sec + JAN_1970);// 构造传输时间戳 data[11] = htonl(NTPFRAC(now.tv_usec)); send(fd, data, 48, 0); } //获取NTP服务器返回的时间 void getNewTime sockaddr_in); memset(&addr_src, 0, addr_len); addr_src.sin_family = AF_INET; addr_src.sin_addr.s_addr = htonl
bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl bzero(void *s, size_t n); %%%% bzero(&servaddr,sizeof(servaddr)); 字节序转换hton函数 servaddr.sin_addr.s_addr=htonl (INADDR_ANY); #include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort ); The htonl() function converts the unsigned integer hostlong from host byte order to network byte order
IPv4中的地址族 serv_addr.sin_family = AF_INET; //32位的IPv4地址, INADDR_ANY表示当前ip serv_addr.sin_addr.s_addr = htonl INADDR_ANY 会自动获取当前服务器的IP 我们看到使用到了 htonl、htons 函数,构造IP地址和端口 为什么构造结构体地址时候使用了 htonl、htons对IP、端口进行了转换 首先我们来看下这几个函数的含义 地址族 含义 htons 把short型数据从主机字节序转化为网络字节序 htonl 把long型数据从主机字节序转化为网络字节序 ntohs 把short型数据从网络字节序转化为主机字节序 ntohl printf("%d",atoi("123")); //output : 123 对比服务端、客户端构造地址代码 服务端 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY 因为客户端接收了字符串IP地址, 所以使用了显示 inet_addr, 返回32位大端序整型数值 htons 将短整型转换为网络字节序, 对于端口来说是比较合适的, 而对于IP类转换的整型数值, 一般需要 htonl
extern uint16_t ntohs (uint16_t __netshort) __THROW __attribute__ ((__const__)); extern uint32_t htonl __const__)); extern uint16_t htons (uint16_t __hostshort) __THROW __attribute__ ((__const__)); htonl htonl中的n表示网络(network)字节序。 htonl中的s表示short,l表示long。 通常s代表2字节short,因此用于端口号转换,l代表4字节long,因此用于IP地址转换。
struct sockaddr_in bindaddr; bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl AF_INET; // Use IPV4 addr.sin_port = htons(port_out); // addr.sin_addr.s_addr = htonl = AF_INET; // Use IPV4 addr.sin_port = htons(port_in); // addr.sin_addr.s_addr = htonl addr.sin_family = AF_INET; addr.sin_port = htons(port_out); addr.sin_addr.s_addr = htonl sockaddr_in); bzero(&ser_addr,addrlen); ser_addr.sin_family=AF_INET; ser_addr.sin_addr.s_addr=htonl
#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_ 例如htonl表示将32位的长 整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。 p = (unsigned char *)&x; printf("%x %x %x %x\n", p[0], p[1], p[2], p[3]); unsigned int y = htonl /byteorder 78 56 34 12 12 34 56 78 即本主机是小端字节序,而经过htonl 转换后为网络字节序,即大端。
SOCK_DGRAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl SOCKSTREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_add=htonl SOCK_DGRAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl
else { cout << "Big endian" << endl; } return 0; } 另外一种方式是借助函数 htonl using namespace std; int main( int argc, char* argv[]) { int i = 0x11223344; if (i == htonl
sockaddr_in addr; addr.sin_family=AF_INET; //本地Ip addr.sin_addr.s_addr=htonl sockaddr_in addr; addr.sin_family=AF_INET; //INADDR_ANY为本地Ip addr.sin_addr.s_addr=htonl
SOCK_DGRAM, 0); memset(&adr, 0, sizeof(adr)); adr.sin_family = AF_INET; adr.sin_addr.s_addr = htonl 加入多播组 //join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]); //join_adr.imr_interface.s_addr = htonl
bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl 用于把目的结构体中指定数目的字节置为0 类似于memset函数,但是比memset少一个容易出BUG的参数 在C语言里,对一块刚申请的内存先清零再使用是必须的 htonl \htons 字节排序函数, htonl是对32位的IPv4地址做转换 htons是对16为的端口号做转换 由机器字节序转变为网络字节序