You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

客户端与服务器双向消息发送问题咨询(附相关代码)

完善UDP客户端与服务器双向消息发送功能

我帮你把UDP双向消息收发的代码补全并优化了,解决了你原代码里的不完整问题,下面是详细的代码和说明:

原代码的核心不足

  • 只实现了客户端socket的初始化,缺少发送消息、接收服务器响应的完整逻辑
  • 没有对应的服务器端代码,双向通信需要两端都具备收发能力
  • 结构体中的u_long body未处理字节序,跨平台运行会出现数据错误
  • 缺少系统调用的错误处理,排查问题很麻烦

完整服务器端代码

#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define PORT 8888
#define BUF_SIZE 1024

int main() {
    int socket_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    struct {
        char head;
        u_long body;
        char tail;
    } msgbuf, recv_buf;

    // 创建UDP socket
    if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 初始化服务器地址结构体
    bzero((char *)&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网卡
    server_addr.sin_port = htons(PORT);

    // 绑定socket到指定端口
    if (bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        close(socket_fd);
        exit(EXIT_FAILURE);
    }

    printf("UDP Server listening on port %d...\n", PORT);

    while (1) {
        // 接收客户端消息
        ssize_t recv_len = recvfrom(socket_fd, &recv_buf, sizeof(recv_buf), 0,
                                    (struct sockaddr *)&client_addr, &client_len);
        if (recv_len < 0) {
            perror("recvfrom failed");
            continue;
        }

        printf("Received from client: head='%c', body=%lu, tail='%c'\n",
               recv_buf.head, ntohl(recv_buf.body), recv_buf.tail);

        // 构造响应消息
        msgbuf.head = 'R';
        msgbuf.body = htonl(ntohl(recv_buf.body) + 1); // 将客户端的body加1返回
        msgbuf.tail = 'r';

        // 发送响应给客户端
        ssize_t send_len = sendto(socket_fd, &msgbuf, sizeof(msgbuf), 0,
                                  (struct sockaddr *)&client_addr, client_len);
        if (send_len < 0) {
            perror("sendto failed");
        } else {
            printf("Sent response to client: head='%c', body=%lu, tail='%c'\n",
                   msgbuf.head, ntohl(msgbuf.body), msgbuf.tail);
        }
    }

    close(socket_fd);
    return 0;
}

完整客户端代码

#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PORT 8888
#define BUF_SIZE 1024

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <server_ip>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int socket_fd;
    struct sockaddr_in dest;
    struct hostent *hostptr;
    struct {
        char head;
        u_long body;
        char tail;
    } msgbuf, recv_buf;

    // 创建UDP socket
    if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 解析服务器IP地址
    hostptr = gethostbyname(argv[1]);
    if (hostptr == NULL) {
        fprintf(stderr, "Unknown host: %s\n", argv[1]);
        close(socket_fd);
        exit(EXIT_FAILURE);
    }

    // 初始化服务器地址结构体
    bzero((char *)&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    bcopy(hostptr->h_addr, (char *)&dest.sin_addr, hostptr->h_length);
    dest.sin_port = htons(PORT);

    // 构造要发送的消息
    msgbuf.head = 'S';
    msgbuf.body = htonl(12345); // 注意转换为网络字节序
    msgbuf.tail = 's';

    printf("Sending to server: head='%c', body=%lu, tail='%c'\n",
           msgbuf.head, ntohl(msgbuf.body), msgbuf.tail);

    // 发送消息到服务器
    ssize_t send_len = sendto(socket_fd, &msgbuf, sizeof(msgbuf), 0,
                              (struct sockaddr *)&dest, sizeof(dest));
    if (send_len < 0) {
        perror("sendto failed");
        close(socket_fd);
        exit(EXIT_FAILURE);
    }

    // 接收服务器的响应
    socklen_t dest_len = sizeof(dest);
    ssize_t recv_len = recvfrom(socket_fd, &recv_buf, sizeof(recv_buf), 0,
                                (struct sockaddr *)&dest, &dest_len);
    if (recv_len < 0) {
        perror("recvfrom failed");
        close(socket_fd);
        exit(EXIT_FAILURE);
    }

    printf("Received from server: head='%c', body=%lu, tail='%c'\n",
           recv_buf.head, ntohl(recv_buf.body), recv_buf.tail);

    close(socket_fd);
    return 0;
}

关键注意事项

  • UDP双向通信逻辑:UDP是无连接协议,客户端通过sendto指定服务器地址发送消息;服务器通过recvfrom获取客户端的地址信息,再用sendto向该地址回复消息,以此实现双向交互
  • 字节序处理:u_long这类多字节类型必须用htonl(主机字节序转网络字节序)和ntohl(网络字节序转主机字节序)转换,否则在不同字节序的机器上会出现数据错乱
  • 错误处理:每个系统调用(socket、bind、sendto、recvfrom)都添加了失败判断,用perror打印错误信息,方便快速排查问题
  • 服务器持续监听:服务器用while(1)循环持续接收客户端消息,支持同时处理多个客户端的请求(UDP无连接特性)

内容的提问来源于stack exchange,提问作者Liana78

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:45:13