当然可以!下面是对 htons()htonl()inet_pton() 等函数的详细讲解,它们是 Linux 下 网络编程(socket 编程) 中的常用工具,用于处理网络字节序的问题。


📌 一、什么是字节序(Endian)

网络通信中,不同平台(x86/ARM)可能使用不同的 字节序(Endian)

  • 大端序(Big-Endian):高位字节存在低地址(网络字节序使用它)
  • 小端序(Little-Endian):高位字节存在高地址(x86 主机使用它)

为了解决不同平台间通信数据的兼容性,Linux 提供了一系列函数用于字节序转换


🧱 二、htons()、htonl() 简介

函数名含义用途
htons()host to network short主机字节序 → 网络字节序(16位)
htonl()host to network long主机字节序 → 网络字节序(32位)
ntohs()network to host short网络字节序 → 主机字节序(16位)
ntohl()network to host long网络字节序 → 主机字节序(32位)

🧪 示例:使用 htons 和 htonl

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    unsigned short port = 8080;       // 16位端口号
    unsigned int ip = 0x7f000001;     // 127.0.0.1 in hex

    unsigned short net_port = htons(port);
    unsigned int net_ip = htonl(ip);

    printf("Host order port: %u\n", port);
    printf("Network order port: %u\n", net_port);

    printf("Host order IP: %u\n", ip);
    printf("Network order IP: %u\n", net_ip);

    return 0;
}

🌐 三、inet_pton() 和 inet_ntop()

这两个函数用于在 字符串形式的 IP 地址 与 二进制格式(网络字节序) 之间转换:

函数含义示例
inet_pton()Presentation → Network字符串 → 二进制 IP
inet_ntop()Network → Presentation二进制 IP → 字符串

✅ 使用 inet_pton 示例

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    const char *ip_str = "192.168.1.1";
    struct in_addr addr;

    int result = inet_pton(AF_INET, ip_str, &addr);
    if (result <= 0) {
        printf("转换失败\n");
    } else {
        printf("inet_pton 成功,网络字节序 IP: 0x%x\n", addr.s_addr);
    }

    return 0;
}

✅ 使用 inet_ntop 示例

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    struct in_addr addr;
    addr.s_addr = htonl(0xc0a80101); // 192.168.1.1

    char ip_str[INET_ADDRSTRLEN];
    const char *result = inet_ntop(AF_INET, &addr, ip_str, INET_ADDRSTRLEN);

    if (result == NULL) {
        printf("转换失败\n");
    } else {
        printf("inet_ntop 成功,IP 字符串: %s\n", ip_str);
    }

    return 0;
}

📦 四、这些函数常用于哪里?

这些函数在 socket 编程中非常常见:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080); // 端口号转换
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); // IP转换

✅ 总结:函数速查表

函数作用参数类型
htons()主机 → 网络(16位)unsigned short
htonl()主机 → 网络(32位)unsigned long
ntohs()网络 → 主机(16位)unsigned short
ntohl()网络 → 主机(32位)unsigned long
inet_pton()字符串 IP → 二进制 IPAF_INETAF_INET6
inet_ntop()二进制 IP → 字符串 IPAF_INETAF_INET6

太好了!下面是一个完整的 Linux 下 C 语言 socket 编程示例,包含:

  • TCP 服务器端和客户端
  • 使用 htons()inet_pton()inet_ntop() 等函数
  • 实现基本的连接、接收、发送逻辑

⚙️ 示例结构

我们将写两个文件:

  1. server.c – TCP 服务器,监听 8080 端口
  2. client.c – TCP 客户端,连接到服务器并发送消息

🧱 1. server.c:TCP 服务器端代码

// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUF_SIZE 1024

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    char buffer[BUF_SIZE];
    socklen_t client_len = sizeof(client_addr);

    // 创建 socket
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("socket 创建失败");
        exit(1);
    }

    // 配置地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY; // 本地任意地址
    server_addr.sin_port = htons(PORT);       // 端口转网络字节序

    // 绑定
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind 失败");
        exit(1);
    }

    // 监听
    if (listen(server_fd, 5) < 0) {
        perror("listen 失败");
        exit(1);
    }

    printf("🚀 服务器监听中,端口 %d...\n", PORT);

    // 接受连接
    client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
    if (client_fd < 0) {
        perror("accept 失败");
        exit(1);
    }

    char client_ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
    printf("✅ 接收到来自 %s:%d 的连接\n", client_ip, ntohs(client_addr.sin_port));

    // 接收数据
    memset(buffer, 0, BUF_SIZE);
    read(client_fd, buffer, BUF_SIZE);
    printf("📩 收到消息: %s\n", buffer);

    // 发送回应
    const char *reply = "Hello from server!";
    write(client_fd, reply, strlen(reply));

    // 关闭连接
    close(client_fd);
    close(server_fd);
    return 0;
}

💻 2. client.c:TCP 客户端代码

// client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUF_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    char buffer[BUF_SIZE];

    // 创建 socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket 创建失败");
        exit(1);
    }

    // 配置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

    // 连接服务器
    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("连接失败");
        exit(1);
    }

    // 发送消息
    const char *msg = "Hello from client!";
    write(sockfd, msg, strlen(msg));

    // 接收回应
    memset(buffer, 0, BUF_SIZE);
    read(sockfd, buffer, BUF_SIZE);
    printf("📩 来自服务器的消息: %s\n", buffer);

    close(sockfd);
    return 0;
}

🛠️ 编译与运行

gcc server.c -o server
gcc client.c -o client

在两个终端中运行:

  1. 第一个终端:
./server
  1. 第二个终端:
./client

你将看到类似输出:

✅ 接收到来自 127.0.0.1:xxxxx 的连接
📩 收到消息: Hello from client!

客户端输出:

📩 来自服务器的消息: Hello from server!

📚 总结:用到了哪些知识点?

用法解释
htons()主机端口 → 网络字节序
inet_pton()IP 字符串 → 二进制地址
inet_ntop()二进制地址 → 字符串(打印用)
read()/write()简单的 socket 通信
socket()/bind()/listen()/accept()/connect()socket 编程核心 API