在网络编程中,我们经常需要处理 IP 地址和端口号等数据,这些数据需要在主机字节序(Host Byte Order)与网络字节序(Network Byte Order)之间进行转换。
什么是字节序?
字节序指的是多字节数据在内存中的存储顺序。
-  
主机字节序:不同的主机可能使用不同的字节序,如:
-  
小端序(Little Endian):低字节在前,高字节在后(如 x86 架构)。
 -  
大端序(Big Endian):高字节在前,低字节在后。
 
 -  
 -  
网络字节序:为了在不同主机之间通信,网络协议规定统一使用大端序(Big Endian)。
 
为了确保数据在网络传输中的一致性,我们需要进行字节序转换。
inet_ntoa
 
作用
inet_ntoa 将一个网络字节序的 IPv4 地址(二进制形式)转换为点分十进制字符串,方便人类阅读。
函数原型
#include <arpa/inet.h> // Linux/Unix
#include <winsock2.h> // Windows
char *inet_ntoa(struct in_addr in); 
参数
-  
in:一个struct in_addr类型的值,表示一个网络字节序的 IPv4 地址。 
返回值
-  
返回一个指向静态分配内存的字符串,表示点分十进制的 IPv4 地址。
 
示例
#include <stdio.h>
#include <arpa/inet.h>int main() {struct in_addr addr;addr.s_addr = htonl(0x7F000001); // 127.0.0.1 的网络字节序char *ip_str = inet_ntoa(addr);printf("IP 地址: %s\n", ip_str); // 输出:IP 地址: 127.0.0.1return 0;
} 
注意事项
-  
inet_ntoa返回的字符串是静态分配的,因此多次调用会覆盖之前的结果。 -  
仅支持 IPv4,不支持 IPv6。
 
htonl
 
作用
htonl(Host TO Network Long)将一个主机字节序的 32 位整数转换为网络字节序。
函数原型
#include <arpa/inet.h> // Linux/Unix
#include <winsock2.h> // Windows
uint32_t htonl(uint32_t hostlong); 
参数
-  
hostlong:一个 32 位整数(如 IPv4 地址或其他网络数据)。 
返回值
-  
返回
hostlong转换为网络字节序后的值。 
示例
#include <stdio.h>
#include <arpa/inet.h>int main() {uint32_t host_long = 0x7F000001; // 127.0.0.1 的主机字节序uint32_t net_long = htonl(host_long);printf("主机字节序: 0x%x\n", host_long); // 输出:主机字节序: 0x7f000001printf("网络字节序: 0x%x\n", net_long); // 输出:网络字节序: 0x0100007freturn 0;
} 
应用场景
-  
发送数据(如 IP 地址或端口号)到网络时,使用
htonl转换为网络字节序。 
相关函数
inet_aton
 
作用
inet_aton 将一个点分十进制字符串表示的 IPv4 地址转换为网络字节序的二进制形式。
函数原型
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp); 
参数
-  
cp:点分十进制字符串,如 "127.0.0.1"。 -  
inp:指向struct in_addr的指针,用于存储转换后的网络字节序地址。 
返回值
-  
成功返回非零,失败返回 0。
 
示例
#include <stdio.h>
#include <arpa/inet.h>int main() {struct in_addr addr;if (inet_aton("127.0.0.1", &addr)) {printf("网络字节序: 0x%x\n", addr.s_addr);} else {printf("转换失败\n");}return 0;
} 
ntohl
 
作用
ntohl(Network TO Host Long)将一个网络字节序的 32 位整数转换为主机字节序。
示例
#include <stdio.h>
#include <arpa/inet.h>int main() {uint32_t net_long = 0x0100007f;uint32_t host_long = ntohl(net_long);printf("主机字节序: 0x%x\n", host_long);return 0;
} 
htons 和 ntohs
 
作用
-  
htons(Host TO Network Short):将主机字节序的 16 位整数转换为网络字节序。 -  
ntohs(Network TO Host Short):将网络字节序的 16 位整数转换为主机字节序。 
示例
#include <stdio.h>
#include <arpa/inet.h>int main() {uint16_t port = 8080;uint16_t net_port = htons(port);printf("网络字节序端口: 0x%x\n", net_port);uint16_t host_port = ntohs(net_port);printf("主机字节序端口: %u\n", host_port);return 0;
} 
inet_ntop 和 inet_pton
 
作用
-  
inet_ntop:将网络字节序的地址(支持 IPv4 和 IPv6)转换为字符串。 -  
inet_pton:将字符串形式的地址(支持 IPv4 和 IPv6)转换为网络字节序。 
示例
#include <stdio.h>
#include <arpa/inet.h>int main() {char str[INET6_ADDRSTRLEN];struct in6_addr ipv6_addr;// IPv6 字符串 -> 网络字节序inet_pton(AF_INET6, "::1", &ipv6_addr);// 网络字节序 -> IPv6 字符串inet_ntop(AF_INET6, &ipv6_addr, str, INET6_ADDRSTRLEN);printf("IPv6 地址: %s\n", str);return 0;
} 
总结
| 函数 | 作用 | 应用场景 | 
|---|---|---|
inet_ntoa | 网络字节序 IPv4 转为点分十进制字符串 | 输出人类可读的 IP 地址 | 
inet_aton | 点分十进制字符串转为网络字节序 IPv4 | 输入 IP 地址 | 
htonl | 主机字节序 32 位整数转为网络字节序 | 发送数据前 | 
ntohl | 网络字节序 32 位整数转为主机字节序 | 接收数据后 | 
htons | 主机字节序 16 位整数(端口号)转为网络字节序 | 发送数据前 | 
ntohs | 网络字节序 16 位整数(端口号)转为主机字节序 | 接收数据后 | 
