【Linux 网络开发】Linux htons()、htonl()、pton()简介(常用在 socket编程中)
常见应用场合
htons()、htonl()常用在 socket编程中服务器的 bind() 之前—— 用于确定服务器协议地址簇变量。
htons()常用于设置端口,htonl常用于设置 IP 地址。
#define SERVER_PORT 8888
server_sock.sin_family = AF_INET;
server_sock.sin_addr = htonl(INADDR_ANY); //侦听任意 IP 地址
server_sock.sin_port = htons(SERVER_PORT); //侦听端口为8888
ret = bind(skt_fd, (struct sockaddr *)(&server_sock), sizeof(server_sock));
也会在客户端 connect() 之前看到:
#define SERVER_PORT 8888
#define SERVER_IP "192.168.1.12"
//2. 调用connect 进行连接服务器
server_sock.sin_family = AF_INET;
inet_pton(AF_INET, SERVER_IP, &(server_sock.sin_addr));//客户端要连接的 IP 地址 192.168.1.12
server_sock.sin_port = htons(SERVER_PORT); //客户端要连接的端口为8888
ret = connect(skt_fd, (struct sockaddr *)(server_sock), sizeof(server_sock));
htons()& htonl()到底是啥子?
#include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);
这两个函数是为了解决大小端问题而生的。
功能:将一个uint16_t或者uint32_t类型数值转换为网络字节序的数值,即大端模式(big-endian)(在主机本身就使用大端字节序时,函数通常被定义为空宏)。
可以通过其英文记忆两个函数:
- h(=host “主机”字节序的意思)
- to:转换
- n(=network "网络"字节序的意思)
- l/s(l=long 64位,s=short 32位)
扩展: 大端模式(TCP / IP网络字节顺序)、小端模式是什么?
举个例子:假定你的port是 0x1234
,
在x86电脑上,0x1234放到内存中实际是:addr addr+1 0x34 0x12
(我们常用的 x86 CPU (intel, AMD) 电脑是小端模式( little-endian),也就是整数的低位字节放在内存的低字节处。)
而在网络字节序里 这个port放到内存中就应该显示成 addr addr+1 0x12 0x34
(而TCP / IP网络字节顺序是大端模式( big-endian),也就是整数的高位字节存放在内存的低地址处。)
htons 的用处就是把实际内存中的整数存放方式调整成“网络字节序”的方式。
inet_pton() 和 inet_ntop() 又是啥子?
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
是为了解决人可读和机器执行的冲突而生的。
将点分十进制表示的字符串形式(人容易读)转换成二进制 Ipv4 或Ipv6 地址(机器容易理解)。
我是这样记忆这个函数的:
- p = people read 意思是人类可读的。
- to 转变
- n = network read 意思是网络识别的
pton(int af, const char *src, void *dst)参数:
- af 必须是AF_INET 或AF_INET6,AF_INET 表示待转换的Ipv4地址,AF_INET6 表示待转换的是Ipv6 地址;
- src:点分十进制表示的字符串
- dst:转换成的地址对象。如果参数 af 被指定为AF_INET,则参数 dst 所指对象应该是一个 struct in_addr 结构体的对象;如果参数af 被指定为AF_INET6,则参数dst 所指对象应该是一个struct in6_addr 结构体的对象。 struct in_addr 结构体的对象只有一个成员,类型为uint32_t,含义是网络字节序的IP地址(不需要再用htonl()函数去转了)
返回值:
- 返回1:成功。
- 返回0:异常,src 不是有效的IP地址。
- 返回-1:失败,如果af 不包含有效的地址族,则 并将errno 设置为EAFNOSUPPORT。
ntop()参数:基本与pton()相同,src 和 dst 相反而已。
ntop()返回值:
inet_ntop()在成功时会返回dst 指针。如果size 的值太小了,那么将会返回NULL 并将errno 设置为ENOSPC。
已淘汰的函数:inet_addr() & inet_aton()/inet_ntoa()
三个函数用于二进制地址格式与点分十进制之间的相互转换,但是仅仅适用于IPv4。inet_pton() 和 inet_ntop() 同时支持IPv4和IPv6。
inet_addr()函数:作用类似于inet_aton()函数
功能:inet_addr()函数用于将点分十进制IP地址转换成网络字节序IP地址;
原型:in_addr_t inet_addr(const char *cp);
返回值:如果正确执行将返回一个无符号长整数型数(in_addr_t)。如果传入的字符串不是一个合法的IP地址,将返回INADDR_NONE;
头文件:arpa/inet.h (Linux)
inet_aton()函数
功能:inet_aton()函数用于将点分十进制IP地址转换成网络字节序IP地址;
原型:int inet_aton(const char *string, struct in_addr *addr);
返回值:如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零;
头文件:sys/socket.h (Linux)
inet_ntoa()函数
功能:inet_ntoa()函数用于网络字节序IP转化点分十进制IP;
原型:char *inet_ntoa (struct in_addr);
返回值:若无错误发生,inet_ntoa()返回一个字符指针。否则的话,返回NULL。其中的数据应在下一个WINDOWS套接口调用前复制出来;
头文件:arpa/inet.h (Linux)
实例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main()
{
int i;
char lo[] = "127.0.0.1";
struct in_addr netAddr;
netAddr.s_addr = inet_addr(lo);
printf("NetIP: 0x%x\n", netAddr.s_addr);
char *strAddr = inet_ntoa(netAddr);
printf("StrIP: %s\n", strAddr);
int ret = inet_aton(strAddr, &netAddr);
printf("NetIP: 0x%x\n", netAddr.s_addr);
return 0;
}
输出结果:
NetIP: 0x100007f(网络序)
StrIP: 127.0.0.1
NetIP: 0x100007f(网络序)