在网络编程中,我们经常需要处理 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.1

    return 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); // 输出:主机字节序: 0x7f000001
    printf("网络字节序: 0x%x\n", net_long); // 输出:网络字节序: 0x0100007f

    return 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;
}

htonsntohs

作用
  • 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_ntopinet_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 位整数(端口号)转为主机字节序接收数据后
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐