【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)参数:

  1. af 必须是AF_INET 或AF_INET6,AF_INET 表示待转换的Ipv4地址,AF_INET6 表示待转换的是Ipv6 地址;
  2. src:点分十进制表示的字符串
  3. 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()

三个函数用于二进制地址格式与点分十进制之间的相互转换,但是仅仅适用于IPv4inet_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(网络序)

 

posted @ 2023-09-06 10:50  FBshark  阅读(1384)  评论(0编辑  收藏  举报