qidao123.com技术社区-IT企服评测·应用市场

标题: UDP 通信详解:`sendto` 和 `recvfrom` 的使用 [打印本页]

作者: 乌市泽哥    时间: 2025-5-9 04:08
标题: UDP 通信详解:`sendto` 和 `recvfrom` 的使用
UDP 通信详解:sendto 和 recvfrom 的使用
1. 概述
UDP(User Datagram Protocol)是一种无连接、不可靠的传输层协议,适用于对实时性要求高但允许少量丢包的场景(如视频流、DNS 查询)。与 TCP 不同,UDP 不必要创建连接,直接通过 sendto 和 recvfrom 发送和接收数据。
本文将详细介绍:
• sendto 和 recvfrom 的函数原型及参数
• UDP 通信的根本流程
• 完备的服务器端和客户端代码示例

2. sendto 函数
sendto 用于通过 UDP 套接字 发送数据。
函数原型
  1. #include <sys/socket.h>
  2. ssize_t sendto(
  3.     int sockfd,                   // 套接字文件描述符
  4.     const void *buf,              // 待发送数据的缓冲区
  5.     size_t len,                   // 数据长度
  6.     int flags,                    // 标志位(通常设为 0)
  7.     const struct sockaddr *dest_addr, // 目标地址
  8.     socklen_t addrlen             // 目标地址长度
  9. );
复制代码
参数说明
参数说明sockfd已创建的 UDP 套接字buf指向待发送数据的缓冲区len数据长度(字节数)flags控制发送行为(通常设为 0)dest_addr目标地址(struct sockaddr_in 或 struct sockaddr)addrlen目标地址结构体的巨细 返回值
• 乐成:返回实际发送的字节数
• 失败:返回 -1,并设置 errno
示例
  1. struct sockaddr_in server_addr;
  2. server_addr.sin_family = AF_INET;
  3. server_addr.sin_port = htons(8888);       // 目标端口
  4. inet_aton("127.0.0.1", &server_addr.sin_addr); // 目标 IP
  5. char *msg = "Hello, UDP Server!";
  6. sendto(sockfd, msg, strlen(msg), 0,
  7.        (struct sockaddr *)&server_addr, sizeof(server_addr));
复制代码

3. recvfrom 函数
recvfrom 用于通过 UDP 套接字 接收数据。
函数原型
  1. #include <sys/socket.h>
  2. ssize_t recvfrom(
  3.     int sockfd,                   // 套接字文件描述符
  4.     void *buf,                    // 接收数据的缓冲区
  5.     size_t len,                   // 缓冲区最大长度
  6.     int flags,                    // 标志位(通常设为 0)
  7.     struct sockaddr *src_addr,    // 存储发送方地址
  8.     socklen_t *addrlen            // 指向地址长度的指针
  9. );
复制代码
参数说明
参数说明sockfd已绑定的 UDP 套接字buf接收数据的缓冲区len缓冲区最大长度flags控制接收行为(通常设为 0)src_addr存储发送方的地址信息(NULL 表示不关心)addrlen指向 src_addr 长度的指针 返回值
• 乐成:返回接收的字节数
• 失败:返回 -1,并设置 errno
示例
  1. struct sockaddr_in client_addr;
  2. socklen_t addr_len = sizeof(client_addr);
  3. char buf[1024];
  4. ssize_t recv_len = recvfrom(sockfd, buf, sizeof(buf), 0,
  5.                            (struct sockaddr *)&client_addr, &addr_len);
  6. if (recv_len > 0) {
  7.     printf("Received from %s:%d: %s\n",
  8.            inet_ntoa(client_addr.sin_addr),
  9.            ntohs(client_addr.sin_port),
  10.            buf);
  11. }
复制代码

4. UDP 通信流程
UDP 通信的根本流程如下:


5. 完备代码示例
5.1 服务器端代码
  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. int main(int argc, char *argv[]) {
  9.     if (argc < 3) {
  10.         fprintf(stderr, "Usage: %s <IP> <PORT>\n", argv[0]);
  11.         exit(EXIT_FAILURE);
  12.     }
  13.     // 1. 创建 UDP 套接字
  14.     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  15.     if (sockfd < 0) {
  16.         perror("socket");
  17.         exit(EXIT_FAILURE);
  18.     }
  19.     // 2. 绑定地址
  20.     struct sockaddr_in addr;
  21.     memset(&addr, 0, sizeof(addr));
  22.     addr.sin_family = AF_INET;
  23.     addr.sin_port = htons(atoi(argv[2]));
  24.     if (inet_aton(argv[1], &addr.sin_addr) == 0) {
  25.         fprintf(stderr, "Invalid IP address\n");
  26.         exit(EXIT_FAILURE);
  27.     }
  28.     if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  29.         perror("bind");
  30.         exit(EXIT_FAILURE);
  31.     }
  32.     printf("Server running on %s:%s\n", argv[1], argv[2]);
  33.     // 3. 接收数据
  34.     char buf[1024];
  35.     struct sockaddr_in client_addr;
  36.     socklen_t addr_len = sizeof(client_addr);
  37.     while (1) {
  38.         memset(buf, 0, sizeof(buf));
  39.         ssize_t recv_len = recvfrom(sockfd, buf, sizeof(buf), 0,
  40.                                    (struct sockaddr *)&client_addr, &addr_len);
  41.         if (recv_len > 0) {
  42.             printf("Received from %s:%d: %s\n",
  43.                    inet_ntoa(client_addr.sin_addr),
  44.                    ntohs(client_addr.sin_port),
  45.                    buf);
  46.         }
  47.     }
  48.     close(sockfd);
  49.     return 0;
  50. }
复制代码
5.2 客户端代码
  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. int main(int argc, char *argv[]) {
  9.     if (argc < 3) {
  10.         fprintf(stderr, "Usage: %s <IP> <PORT>\n", argv[0]);
  11.         exit(EXIT_FAILURE);
  12.     }
  13.     // 1. 创建 UDP 套接字
  14.     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  15.     if (sockfd < 0) {
  16.         perror("socket");
  17.         exit(EXIT_FAILURE);
  18.     }
  19.     // 2. 设置目标地址
  20.     struct sockaddr_in server_addr;
  21.     memset(&server_addr, 0, sizeof(server_addr));
  22.     server_addr.sin_family = AF_INET;
  23.     server_addr.sin_port = htons(atoi(argv[2]));
  24.     if (inet_aton(argv[1], &server_addr.sin_addr) == 0) {
  25.         fprintf(stderr, "Invalid IP address\n");
  26.         exit(EXIT_FAILURE);
  27.     }
  28.     // 3. 发送数据
  29.     char buf[1024];
  30.     while (1) {
  31.         printf("Input message: ");
  32.         fgets(buf, sizeof(buf), stdin);
  33.         buf[strlen(buf) - 1] = '\0';  // 去掉换行符
  34.         sendto(sockfd, buf, strlen(buf), 0,
  35.                (struct sockaddr *)&server_addr, sizeof(server_addr));
  36.     }
  37.     close(sockfd);
  38.     return 0;
  39. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4