客户端与服务器双向消息发送问题咨询(附相关代码)
完善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
相关产品推荐
相关产品推荐

