计算机网络 —— 网络编程(接口命令梳理)

计算机网络 ------ 网络编程(接口命令梳理)

  • UDP接口
      • [1. socket()](#1. socket())
      • [2. bind()](#2. bind())
      • 3.sendto()
      • [4. recvfrom()](#4. recvfrom())
      • [5. close()](#5. close())
      • [6. connect() (可选)](#6. connect() (可选))
  • TCP接口
      • [1. socket()](#1. socket())
      • [2. bind()](#2. bind())
      • [3. listen()](#3. listen())
      • [4. accept()](#4. accept())
      • [5. connect()](#5. connect())
      • [6. send() 和 recv()](#6. send() 和 recv())
      • [7. close()](#7. close())
  • 网络字节序转换函数
      • [1. htons()](#1. htons())
      • [2. htonl()](#2. htonl())
      • [3. ntohs()](#3. ntohs())
      • [4. ntohl()](#4. ntohl())
      • 使用场景
      • 示例
  • IP地址处理相关函数
      • [1. inet_aton()](#1. inet_aton())
      • [2. inet_ntoa()](#2. inet_ntoa())
      • [3. inet_pton()](#3. inet_pton())
      • [4. inet_ntop()](#4. inet_ntop())
      • 使用场景
      • 示例

我们之前学习了一大堆的UDP和TCP的接口,一开始肯定会很晕,这篇博客主要帮大家梳理一下这些接口,以及接口中的参数:

UDP接口

UDP的接口就4个:socket,bind,sendto,recvfrom

在Linux中,UDP(用户数据报协议)网络接口是指用于创建、配置和管理UDP套接字的API和工具。这些接口允许应用程序通过UDP协议发送和接收数据包。以下是与UDP相关的几个主要方面:

当然,下面是UDP接口中常用函数的详细描述,包括它们的参数、返回值以及常见错误代码。这些信息有助于理解每个函数的功能和如何正确使用它们进行UDP编程。

1. socket()

  • 功能:创建一个套接字。
  • 原型
c 复制代码
int socket(int domain, int type, int protocol);
  • 参数
  • domain:指定地址族(如 AF_INET 表示IPv4)。
  • type:指定套接字类型(如 SOCK_DGRAM 表示UDP)。
  • protocol:通常设置为0,表示使用默认协议(对于UDP来说是 IPPROTO_UDP)。
  • 返回值
  • 成功时返回一个新的套接字描述符(非负整数)。
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EMFILE 表示文件描述符已满,ENFILE 表示系统文件表已满)。

2. bind()

  • 功能:将套接字绑定到特定的本地地址和端口。
  • 原型
c 复制代码
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数
  • sockfd:由 socket() 创建的套接字描述符。
  • addr:指向包含地址信息的结构体(如 struct sockaddr_in)的指针。
  • addrlen:地址结构体的大小。
  • 返回值
  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EADDRINUSE 表示地址已在使用,EINVAL 表示无效参数)。

3.sendto()

  • 功能:向指定的地址发送数据报文。
  • 原型
c 复制代码
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
  • 参数
  • sockfd:由 socket() 创建的套接字描述符。
  • buf:指向要发送的数据缓冲区的指针。
  • len:要发送的数据长度(以字节为单位)。
  • flags:提供对行为的额外控制(例如,MSG_DONTWAIT 表示非阻塞操作)。
  • dest_addr:指向目标地址信息的结构体(如 struct sockaddr_in)的指针。
  • addrlen:地址结构体的大小。
  • 返回值
  • 成功时返回实际发送的字节数。
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EAGAINEWOULDBLOCK 表示在非阻塞模式下没有数据可写,EHOSTUNREACH 表示主机不可达)。

4. recvfrom()

  • 功能:从指定的地址接收数据报文。
  • 原型
c 复制代码
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
  • 参数
  • sockfd:由 socket() 创建的套接字描述符。
  • buf:指向用于存储接收到的数据的缓冲区的指针。
  • len:要接收的最大数据量(以字节为单位)。
  • flags:提供对行为的额外控制(例如,MSG_DONTWAIT 表示非阻塞操作,MSG_PEEK 表示预览数据而不移除它)。
  • src_addr:指向存储源地址信息的结构体(如 struct sockaddr_in)的指针。
  • addrlen:指向变量的指针,该变量保存地址结构体的大小。
  • 返回值
  • 成功时返回实际接收到的字节数。
  • 如果对方关闭了连接,recvfrom() 返回 0(不过在UDP中这不太常见,因为UDP是无连接的)。
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EAGAINEWOULDBLOCK 表示在非阻塞模式下没有数据可读,ECONNREFUSED 表示连接被拒绝)。

5. close()

  • 功能:关闭套接字,释放相关资源。
  • 原型
c 复制代码
int close(int fd);
  • 参数
  • fd:要关闭的文件描述符或套接字描述符。
  • 返回值
  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EBADF 表示无效文件描述符)。

6. connect() (可选)

虽然UDP是无连接的,但你可以选择调用 connect() 来简化后续的 send()recv() 调用。一旦调用了 connect(),你就可以使用 send()recv() 而不是 sendto()recvfrom(),因为目的地址已经确定。

  • 功能:为UDP套接字设置默认的目的地址。
  • 原型
c 复制代码
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数
  • sockfd:由 socket() 创建的未连接套接字描述符。
  • addr:指向包含服务器地址信息的结构体(如 struct sockaddr_in)的指针。
  • addrlen:地址结构体的大小。
  • 返回值
  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EISCONN 表示套接字已经是连接状态,EINVAL 表示无效参数)。

下面写的什么不重要,主要是要理清过程

cpp 复制代码
// udp_server.cpp
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

#define SERVER_PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    char buffer[BUFFER_SIZE];
    struct sockaddr_in servaddr, cliaddr;
    socklen_t len = sizeof(cliaddr);

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        std::cerr << "Socket creation error" << std::endl;
        return -1;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    memset(&cliaddr, 0, sizeof(cliaddr));

    // 设置服务器地址和端口
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(SERVER_PORT);

    // 绑定套接字到服务器地址和端口
    if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        std::cerr << "Bind error" << std::endl;
        close(sockfd);
        return -1;
    }

    std::cout << "UDP Server listening on port " << SERVER_PORT << std::endl;
		
		//发送数据
    while (true) {
        ssize_t numBytesReceived = recvfrom(sockfd, buffer, BUFFER_SIZE, 0,
                                            (struct sockaddr *)&cliaddr, &len);
        if (numBytesReceived < 0) {
            std::cerr << "Recvfrom error" << std::endl;
            close(sockfd);
            return -1;
        } else if (numBytesReceived == 0) {
            std::cout << "Client disconnected" << std::endl;
            break;
        } else {
            buffer[numBytesReceived] = '\0'; // 确保字符串以null结尾
            std::cout << "Received message: " << buffer << " from "
                      << inet_ntoa(cliaddr.sin_addr) << ":" << ntohs(cliaddr.sin_port) << std::endl;
        }
    }

    // 关闭套接字
    close(sockfd);

    return 0;
}
cpp 复制代码
// udp_client.cpp
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

#define SERVER_ADDRESS "127.0.0.1"
#define SERVER_PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    const char *message = "Hello, UDP Server!";
    char buffer[BUFFER_SIZE]; // 实际上在这个简单的客户端示例中,我们不会使用这个缓冲区来接收数据

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        std::cerr << "Socket creation error" << std::endl;
        return -1;
    }

    // 设置服务器地址和端口
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERVER_PORT);
    // 将服务器地址从文本转换为二进制形式
    if (inet_pton(AF_INET, SERVER_ADDRESS, &servaddr.sin_addr) <= 0) {
        std::cerr << "Invalid address/ Address not supported" << std::endl;
        close(sockfd);
        return -1;
    }

    // 发送数据到服务器
    ssize_t numBytesSent = sendto(sockfd, message, strlen(message), 0,
                                  (const struct sockaddr *)&servaddr, sizeof(servaddr));
    if (numBytesSent < 0) {
        std::cerr << "Sendto error" << std::endl;
        close(sockfd);
        return -1;
    } else {
        std::cout << "Message sent: " << message << std::endl;
    }

    // 关闭套接字(对于UDP,这通常是可选的,因为UDP是无连接的)
    close(sockfd);

    return 0;
}

TCP接口

相比UDP的接口,TCP的接口多了几个socket,bind,listen(服务端),accpect(服务端),connect(客户端),send(write),recv(read)

在Linux中,TCP(传输控制协议)接口主要通过套接字API来实现。TCP是一种面向连接的、可靠的传输层协议,确保数据包按顺序无误地从一个应用程序传输到另一个应用程序。以下是与TCP相关的几个关键方面:

当然,下面是TCP接口中常用函数的详细描述,包括它们的参数、返回值以及常见错误代码。这些信息有助于理解每个函数的功能和如何正确使用它们。

1. socket()

  • 功能:创建一个套接字。
  • 原型
c 复制代码
int socket(int domain, int type, int protocol);
  • 参数
    • domain:指定地址族(如 AF_INET 表示IPv4)。
    • type:指定套接字类型(如 SOCK_STREAM 表示TCP)。
    • protocol:通常设置为0,表示使用默认协议。
  • 返回值
    • 成功时返回一个新的套接字描述符(非负整数)。
    • 失败时返回 -1,并设置 errno 指出错误原因(例如,EMFILE 表示文件描述符已满,ENFILE 表示系统文件表已满)。

2. bind()

  • 功能:将套接字绑定到特定的本地地址和端口。
  • 原型
c 复制代码
 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数
  • sockfd:由 socket() 创建的套接字描述符。
  • addr:指向包含地址信息的结构体(如 struct sockaddr_in)的指针。
  • addrlen:地址结构体的大小。
  • 返回值
  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EADDRINUSE 表示地址已在使用,EINVAL 表示无效参数)。

3. listen()

  • 功能:将套接字标记为被动监听状态,准备接受传入连接请求。
  • 原型
c 复制代码
 int listen(int sockfd, int backlog);
  • 参数
  • sockfd:由 socket() 创建的套接字描述符。
  • backlog:指定等待连接队列的最大长度。
  • 返回值
  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EINVAL 表示无效参数,ENOTSOCK 表示文件描述符不是一个套接字)。

4. accept()

  • 功能:从已完成连接队列中提取下一个挂起的连接,并创建一个新的套接字用于与客户端通信。
  • 原型
c 复制代码
  int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 参数
  • sockfd:由 socket() 创建并已经调用 listen() 的套接字描述符。
  • addr:指向存储客户端地址信息的结构体(如 struct sockaddr_in)的指针。
  • addrlen:指向变量的指针,该变量保存地址结构体的大小。
  • 返回值
  • 成功时返回一个新的套接字描述符,用于与客户端通信。
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EAGAINEWOULDBLOCK 表示在非阻塞模式下没有可用连接,EBADF 表示无效文件描述符)。

5. connect()

  • 功能:客户端主动发起与服务器的连接请求。
  • 原型
c 复制代码
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数
  • sockfd:由 socket() 创建的未连接套接字描述符。
  • addr:指向包含服务器地址信息的结构体(如 struct sockaddr_in)的指针。
  • addrlen:地址结构体的大小。
  • 返回值
  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,ECONNREFUSED 表示连接被拒绝,ETIMEDOUT 表示连接超时,EINPROGRESS 表示在非阻塞模式下连接正在尝试建立但尚未完成)。

6. send() 和 recv()

  • 功能:分别用于发送和接收数据。
  • 原型
c 复制代码
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • 参数
  • sockfd:由 socket() 创建的套接字描述符。
  • buf:指向数据缓冲区的指针。
  • len:要发送或接收的数据长度(以字节为单位)。
  • flags:提供对行为的额外控制(例如,MSG_DONTWAIT 表示非阻塞操作)。
  • 返回值
  • 成功时,send() 返回实际发送的字节数,recv() 返回实际接收到的字节数。
  • 如果对方关闭了连接,recv() 返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EAGAINEWOULDBLOCK 表示在非阻塞模式下没有数据可读/写,EPIPE 表示试图向已关闭的连接写入数据)。

上面的函数,除了socket和accpect成功时返回一个非0的文件描述符,其他的函数都是返回

7. close()

  • 功能:关闭套接字,释放相关资源。
  • 原型
c 复制代码
int close(int fd);
  • 参数
  • fd:要关闭的文件描述符或套接字描述符。
  • 返回值
  • 成功时返回 0
  • 失败时返回 -1,并设置 errno 指出错误原因(例如,EBADF 表示无效文件描述符)。

下面的代码写的什么不重要,主要是理清这个TCP建立的过程:

下面是一个使用C++实现的简单TCP服务器和客户端示例。

首先是TCP服务器代码:

cpp 复制代码
// tcp_server.cpp
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
 
#define PORT 8080
#define BUFFER_SIZE 1024
 
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    const char *hello = "Hello from server";
 
    // 创建套接字文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
 
    // 绑定套接字到端口
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
 
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
 
    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
 
    // 接受客户端连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
        perror("accept");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
 
    // 读取客户端消息
    read(new_socket, buffer, BUFFER_SIZE);
    std::cout << "Message from client: " << buffer << std::endl;
 
    // 发送消息给客户端
    send(new_socket, hello, strlen(hello), 0);
    std::cout << "Hello message sent\n";
 
    // 关闭套接字
    close(new_socket);
    close(server_fd);
 
    return 0;
}

接下来是TCP客户端代码:

cpp 复制代码
// tcp_client.cpp
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
 
#define PORT 8080
#define BUFFER_SIZE 1024
 
int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *hello = "Hello from client";
    char buffer[BUFFER_SIZE] = {0};
 
    // 创建套接字文件描述符
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        std::cerr << "\n Socket creation error \n";
        return -1;
    }
 
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
 
    // 将服务器地址转换为二进制形式
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        std::cerr << "\nInvalid address/ Address not supported \n";
        return -1;
    }
 
    // 连接服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        std::cerr << "\nConnection Failed \n";
        return -1;
    }
 
    // 发送消息给服务器
    send(sock, hello, strlen(hello), 0);
    std::cout << "Hello message sent\n";
 
    // 读取服务器消息
    read(sock, buffer, BUFFER_SIZE);
    std::cout << "Message from server: " << buffer << std::endl;
 
    // 关闭套接字
    close(sock);
 
    return 0;
}

网络字节序转换函数

当然,下面是一些常用的网络字节序转换函数的详细描述,包括它们的参数、返回值以及使用说明。这些函数用于在网络编程中正确处理不同平台之间的字节序差异,确保数据在不同主机间传输时的一致性。

1. htons()

  • 功能:将一个无符号短整型(通常是16位)从主机字节序转换为网络字节序(大端字节序)。
  • 原型
c 复制代码
uint16_t htons(uint16_t hostshort);
  • 参数
  • hostshort:要转换的16位无符号整数。
  • 返回值
  • 返回转换后的16位无符号整数,在网络字节序表示形式下。

2. htonl()

  • 功能:将一个无符号长整型(通常是32位)从主机字节序转换为网络字节序(大端字节序)。
  • 原型
c 复制代码
uint32_t htonl(uint32_t hostlong);
  • 参数
  • hostlong:要转换的32位无符号整数。
  • 返回值
  • 返回转换后的32位无符号整数,在网络字节序表示形式下。

3. ntohs()

  • 功能:将一个无符号短整型(通常是16位)从网络字节序转换为主机字节序。
  • 原型
c 复制代码
uint16_t ntohs(uint16_t netshort);
  • 参数
  • netshort:要转换的16位无符号整数,假设它是网络字节序。
  • 返回值
  • 返回转换后的16位无符号整数,在主机字节序表示形式下。

4. ntohl()

  • 功能:将一个无符号长整型(通常是32位)从网络字节序转换为主机字节序。
  • 原型
c 复制代码
uint32_t ntohl(uint32_t netlong);
  • 参数
  • netlong:要转换的32位无符号整数,假设它是网络字节序。
  • 返回值
  • 返回转换后的32位无符号整数,在主机字节序表示形式下。

使用场景

这些函数在网络编程中非常常用,尤其是在创建和解析IP地址、端口号等需要跨平台一致性的数据结构时。例如:

  • 当设置套接字地址结构(如 struct sockaddr_in)中的端口号或IP地址时,应该使用 htons()htonl() 将主机字节序转换为网络字节序。
  • 当接收到来自网络的数据并解析其中的端口号或IP地址时,应该使用 ntohs()ntohl() 将网络字节序转换为主机字节序。

示例

假设你有一个端口号 port 和一个IP地址 ip_address,你需要将它们设置到 struct sockaddr_in 结构体中:

c 复制代码
#include <arpa/inet.h>
#include <netinet/in.h>

uint16_t port = 8080;
uint32_t ip_address = inet_addr("192.168.1.1");

struct sockaddr_in server_addr;

// 设置服务器地址结构体
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);        // 端口从主机字节序转换为网络字节序
server_addr.sin_addr.s_addr = htonl(ip_address); // IP地址从主机字节序转换为网络字节序

同样地,当你从网络接收到数据并需要解析出端口号或IP地址时,你可以这样做:

c 复制代码
uint16_t received_port = ntohs(server_addr.sin_port);         // 网络字节序转换为主机字节序
uint32_t received_ip = ntohl(server_addr.sin_addr.s_addr);    // 网络字节序转换为主机字节序

这些字节序转换函数是网络编程中不可或缺的一部分,确保了数据在网络传输过程中的一致性和正确性。了解如何正确使用这些函数可以帮助你编写更可靠、跨平台兼容的网络应用程序。每个函数都简单明了,但它们在网络通信中的作用至关重要。

IP地址处理相关函数

下面是与IP地址处理相关的常用函数的详细描述,包括它们的参数、返回值以及使用说明。这些函数用于将IP地址在字符串和二进制形式之间进行转换,并验证IP地址的有效性。

1. inet_aton()

  • 功能 :将点分十进制表示的IPv4地址字符串转换为二进制形式并存储到 struct in_addr 结构体中。
  • 原型
c 复制代码
 int inet_aton(const char *cp, struct in_addr *inp);
  • 参数
  • cp:指向包含点分十进制IPv4地址字符串(如 "192.168.1.1")的指针。
  • inp:指向 struct in_addr 的指针,用于存储转换后的二进制地址。
  • 返回值
  • 成功时返回 1
  • 如果输入的字符串不是一个有效的IPv4地址,则返回 0

2. inet_ntoa()

  • 功能 :将 struct in_addr 中的IPv4地址转换为点分十进制字符串。
  • 原型
c 复制代码
char *inet_ntoa(struct in_addr in);
  • 参数
  • in:包含要转换的IPv4地址的 struct in_addr 结构体。
  • 返回值
  • 返回一个指向静态分配的字符数组的指针,该数组包含转换后的点分十进制字符串。注意,这个函数不是线程安全的,因为所有调用共享同一个静态缓冲区。

3. inet_pton()

  • 功能:将IP地址从字符串格式转换为网络字节序的二进制格式,支持IPv4和IPv6。
  • 原型
c 复制代码
int inet_pton(int af, const char *src, void *dst);
  • 参数
  • af:地址族,可以是 AF_INET(IPv4)或 AF_INET6(IPv6)。
  • src:指向包含IP地址字符串的指针。
  • dst:指向用于存储转换后的二进制地址的缓冲区。
  • 返回值
  • 成功时返回 1
  • 如果输入的字符串不是一个有效的IP地址,则返回 0
  • 如果地址族不支持,则返回 -1 并设置 errno

4. inet_ntop()

  • 功能:将网络字节序的二进制格式IP地址转换为字符串格式,支持IPv4和IPv6。
  • 原型
c 复制代码
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
  • 参数
  • af:地址族,可以是 AF_INET(IPv4)或 AF_INET6(IPv6)。
  • src:指向包含二进制IP地址的缓冲区。
  • dst:指向用于存储转换后的字符串的缓冲区。
  • size:指定 dst 缓冲区的大小。
  • 返回值
  • 成功时返回指向 dst 的指针。
  • 如果转换失败,则返回 NULL 并设置 errno(例如,ENOSPC 表示提供的缓冲区太小)。

使用场景

这些函数在网络编程中非常有用,尤其是在需要处理IP地址时。例如:

  • 当你需要将用户输入的IP地址字符串转换为可以用于套接字结构中的二进制形式时,可以使用 inet_aton()inet_pton()
  • 当你需要将套接字结构中的二进制IP地址转换为可读的字符串形式时,可以使用 inet_ntoa()inet_ntop()

示例

假设你有一个IP地址字符串 "192.168.1.1" 和一个 struct sockaddr_in 结构体:

c 复制代码
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>

int main() {
    const char *ip_str = "192.168.1.1";
    struct in_addr ip_addr;
    
    // 将字符串形式的IPv4地址转换为二进制形式
    if (inet_aton(ip_str, &ip_addr) == 0) {
        fprintf(stderr, "Invalid IP address\n");
        return 1;
    }

    printf("Binary IP address: %u.%u.%u.%u\n",
           (unsigned char)(ip_addr.s_addr),
           (unsigned char)(ip_addr.s_addr >> 8),
           (unsigned char)(ip_addr.s_addr >> 16),
           (unsigned char)(ip_addr.s_addr >> 24));

    // 将二进制形式的IPv4地址转换回字符串形式
    char ip_str_converted[INET_ADDRSTRLEN];
    if (inet_ntop(AF_INET, &ip_addr, ip_str_converted, sizeof(ip_str_converted)) == NULL) {
        perror("inet_ntop failed");
        return 1;
    }
    printf("Converted IP address string: %s\n", ip_str_converted);

    return 0;
}

对于IPv6地址,你可以使用 inet_pton()inet_ntop() 来进行类似的转换操作。

这些IP地址处理函数在网络编程中非常重要,确保了IP地址在不同表示形式之间的正确转换。了解如何正确使用这些函数可以帮助你编写更可靠、跨平台兼容的网络应用程序。每个函数都有其特定的作用,并通过返回值提供详细的错误信息,帮助你在遇到问题时进行调试和错误处理。

相关推荐
域智盾-运营小韩2 小时前
怎么管理电脑usb接口,分享四种USB端口管理方法
服务器·网络·负载均衡
犹若故人归2 小时前
计算机网络、嵌入式等常见问题简答
java·网络·嵌入式硬件·计算机网络·intellij-idea
LLLuckyGirl~3 小时前
计算机网络之---信号与编码
网络·计算机网络
jiecy3 小时前
OSPF浅析
网络
web135956097054 小时前
桌面运维岗面试三十问
运维·网络
黑客-秋凌4 小时前
计算机网络:网络层
arm开发·计算机网络
雪球不会消失了5 小时前
06-RabbitMQ基础
java·网络·spring cloud·mq
自由自在的小Bird6 小时前
计算机网路HTTP、TCP详解
网络·网络协议·http
komo莫莫da6 小时前
第6章——HTTP首部
网络·网络协议·http
大丈夫立于天地间6 小时前
OSPF - LSA对照表
网络·网络协议·学习·算法·信息与通信