【C++网络编程】(二)Linux平台下UDP客户/服务端程序

Linux平台下UDP客户/服务端程序

图片来源:https://subingwen.cn/linux/udp/

UDP服务器无法直接检测客户端断开连接。

UDP 服务端

server.cpp

cpp 复制代码
#include <iostream>
#include <cstdlib>      // std::exit
#include <cstring>      // memset
#include <arpa/inet.h>  // socket, bind, recvfrom, sendto,SOCK_DGRAM
#include <unistd.h>     // close

int main()
{
    // 1. 创建 UDP 套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);  // 创建一个UDP套接字
    if (sockfd == -1)
    {
        perror("socket");  // 错误处理
        std::exit(EXIT_FAILURE);
    }

    // 2. 将socket()返回值和本地的IP端口绑定到一起
    sockaddr_in addr;                     // 用于存储地址信息
    addr.sin_family = AF_INET;            // 地址族,IPv4
    addr.sin_port = htons(10000);         // 转换服务器的端口号10000为网络字节序
    addr.sin_addr.s_addr = INADDR_ANY;    // 绑定到任意IP地址
    // inet_pton(AF_INET, "172.31.108.107", &addr.sin_addr.s_addr); // 指定IP地址

    int ret = bind(sockfd, (sockaddr*)&addr, sizeof(addr)); // 绑定套接字到地址
    if (ret == -1)
    {
        perror("bind");  // 错误处理
        std::exit(EXIT_FAILURE);
    }

    // 3. 和客户端通信
    while (true)
    {
        char buf[1024];  // 接收缓冲区
        memset(buf, 0, sizeof(buf));  // 清零缓冲区
        
        sockaddr_in cliaddr;           // 用于存储客户端地址信息
        socklen_t clilen = sizeof(cliaddr); // 客户端地址结构的大小
        
        // 接收数据
        int len = recvfrom(sockfd, buf, sizeof(buf), 0, (sockaddr*)&cliaddr, &clilen); // 从客户端读取数据
        if (len > 0)
        {
            std::cout << "客户端: " << buf << std::endl;  // 打印客户端发送的消息

            // 回复客户端
            std::string response = "你好, 客户端...\n";
            sendto(sockfd, response.c_str(), response.size(), 0, (sockaddr*)&cliaddr, clilen); // 发送响应
        }
        else
        {
            perror("recvfrom");  // 错误处理
            break;
        }
    }

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

    return 0;
}

编译与运行

bash 复制代码
g++ server.cpp -o server
./server

UDP 客户端

client.cpp

cpp 复制代码
#include <iostream>
#include <cstdlib>      // std::exit
#include <cstring>      // memset, strlen
#include <arpa/inet.h>  // socket, sendto, recvfrom, inet_pton, htons
#include <unistd.h>     // close, sleep

int main()
{
    // 1. 创建通信的套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);  // 创建一个UDP套接字
    if (sockfd == -1)
    {
        perror("socket");  // 错误处理
        std::exit(EXIT_FAILURE);
    }

    // 2. 准备服务器地址信息
    sockaddr_in addr;               // 用于存储服务器地址信息
    addr.sin_family = AF_INET;      // 地址族,IPv4
    addr.sin_port = htons(10000);   // 大端端口转换
    inet_pton(AF_INET, "172.31.108.107", &addr.sin_addr.s_addr); // 将IP地址转换为网络字节顺序

    // 3. 和服务器端通信
    int number = 0;
    while (true)
    {
        // 发送数据
        char buf[1024];                 // 数据缓冲区
        sprintf(buf, "你好, 服务器...\n", number++);  // 格式化字符串
        sendto(sockfd, buf, strlen(buf), 0, (sockaddr*)&addr, sizeof(addr));  // 发送数据
        
        // 接收数据
        memset(buf, 0, sizeof(buf));  // 清空缓冲区
        sockaddr_in recv_addr;         // 用于存储服务器地址信息
        socklen_t addr_len = sizeof(recv_addr);
        int len = recvfrom(sockfd, buf, sizeof(buf), 0, (sockaddr*)&recv_addr, &addr_len);  // 从服务器读取数据
        if (len > 0)
        {
            std::cout << "服务器: " << buf;   // 打印服务器发送的消息
        }
        else
        {
            perror("recvfrom"); 
            break;
        }
        sleep(1);   // 每隔1秒发送一条数据
    }

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

    return 0;
}

编译与运行

bash 复制代码
g++ client.cpp -o client
./client

相关头文件介绍

使用到的函数和宏除了<sys/socket.h>recvfromsendtoSOCK_DGRAM,其他使用到的函数和宏与TCP网络通信中的基本一致。

<sys/socket.h>

  • bytes_sent = recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); :用于接收数据报文,适用于无连接的套接字(如 UDP)。它允许从任何源地址接收数据。成功时返回接收到的字节数,失败时返回 -1。 参数:

    • sockfd:接收数据的套接字描述符。
    • buf:指向接收数据的缓冲区。
    • len:缓冲区的长度,表示最大接收字节数。
    • flags:接收选项的标志,通常为 0
    • src_addr:指向 sockaddr 结构体的指针,用于存储发送方的地址信息。
    • addrlen:指向 socklen_t 类型的指针,表示 src_addr 结构体的长度。
  • bytes_sent = sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) :用于发送数据报文,适用于无连接的套接字(如 UDP)。它允许将数据发送到指定的目标地址。成功时返回实际发送的字节数,失败时返回 -1。 参数:

    • sockfd:发送数据的套接字描述符。
    • buf:指向要发送数据的缓冲区。
    • len:要发送的字节数。
    • flags:发送选项的标志,通常为 0
    • dest_addr:指向目标地址的 sockaddr 结构体。
    • addrlen:目标地址的长度。
  • SOCK_DGRAM:用于创建数据报套接字,表示使用无连接的 UDP 协议进行数据传输。

相关推荐
唐诺1 小时前
几种广泛使用的 C++ 编译器
c++·编译器
冷眼看人间恩怨2 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客2 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin2 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos4 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室4 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0015 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我585 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc5 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很5 小时前
C++ 集合 list 使用
c++