TCP Socket服务器跨端口回复客户端失败问题排查
TCP跨端口回复问题的修复方案
核心问题分析
当前代码无法跨端口回复的本质原因是TCP面向连接的特性:你通过accept得到的new_socket绑定的是1345端口,所有通过该socket发送的数据,源端口都会是1345。要从2345端口回复,必须创建新的socket并绑定到2345端口,再与客户端建立连接后发送。此外代码还存在多处语法、逻辑错误,具体如下:
代码中的错误点
listen调用位置错误:listen只需调用一次,放在while循环外即可,重复调用会导致连接异常。- 语法错误:
accept语句末尾缺少分号。 - 发送参数错误:
sizeof(sendMessage)是指针的字节数(通常4/8字节),不是实际消息长度,应使用strlen(sendMessage)。 - 发送循环逻辑错误:成功发送后直接
break未处理剩余字节;且sent_bytes -= res_sock未配合指针偏移,会重复发送同一内容。 - 变量名错误:
htons(destPort)中的destPort未定义,应为dstPort。 - 未处理接收返回值:直接设置
msg_received=true,需判断recvfrom返回值>0才代表接收成功。 - 文件句柄泄漏:
new_socket使用后未关闭,会耗尽系统资源。 - 未定义变量:
ret_bind、new_socket、ip_src、ip_dst、cfg等变量未在代码中声明。
修复后的代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdbool.h> #define MSS 1024 // 假设为全局或传入的服务端IP struct in_addr ip_src; // 客户端IP由accept自动获取,无需提前定义 char* getTCPMessageOut() { // 根据实际业务实现消息生成逻辑 static char msg[] = "Response from port 2345"; return msg; } void *CreateTCPSocket(void *p) { int srcPort = 1345; int dstPort = 2345; struct sockaddr_in sockaddr_from; struct sockaddr_in client_addr; int client_addr_len = sizeof(client_addr); uint8_t recv_message[MSS]; bool msg_received = false; int ret_bind; int new_socket; // 创建接收用的TCP Socket(绑定1345端口) int fd_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd_sock == -1){ perror("socket create failed"); exit(1); } // 配置接收端口地址 memset(&sockaddr_from, 0, sizeof(sockaddr_from)); sockaddr_from.sin_family = AF_INET; sockaddr_from.sin_port = htons(srcPort); sockaddr_from.sin_addr = ip_src; if((ret_bind = bind(fd_sock, (struct sockaddr*)&sockaddr_from, sizeof(sockaddr_from))) < 0){ perror("ERROR bind"); close(fd_sock); exit(1); } // listen仅需调用一次 if (listen(fd_sock, 100) < 0) { perror("listen"); close(fd_sock); exit(EXIT_FAILURE); } while(1){ new_socket = accept(fd_sock, (struct sockaddr*)&client_addr,(socklen_t*)&client_addr_len); if (new_socket < 0){ perror("accept failed"); continue; } // 接收客户端消息 int res_sock = recv(new_socket, recv_message, MSS, 0); if (res_sock > 0){ msg_received = true; recv_message[res_sock] = '\0'; // 确保字符串结束 printf("Received: %s\n", recv_message); } else { close(new_socket); continue; } // 创建用于回复的新Socket,绑定2345端口 int send_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (send_sock == -1){ perror("send socket create failed"); close(new_socket); continue; } // 配置回复Socket的源端口(2345) struct sockaddr_in send_addr; memset(&send_addr, 0, sizeof(send_addr)); send_addr.sin_family = AF_INET; send_addr.sin_port = htons(dstPort); send_addr.sin_addr = ip_src; if(bind(send_sock, (struct sockaddr*)&send_addr, sizeof(send_addr)) < 0){ perror("bind send socket failed"); close(send_sock); close(new_socket); continue; } // 连接到客户端的地址(IP+客户端源端口) if(connect(send_sock, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0){ perror("connect to client failed"); close(send_sock); close(new_socket); continue; } char* sendMessage = getTCPMessageOut(); int total_bytes = strlen(sendMessage); int sent_total = 0; // 循环发送全部消息 while (sent_total < total_bytes) { res_sock = send(send_sock, sendMessage + sent_total, total_bytes - sent_total, MSG_NOSIGNAL); if (res_sock < 0){ perror("Send Error"); break; } sent_total += res_sock; } // 关闭所有socket,避免句柄泄漏 close(send_sock); close(new_socket); } close(fd_sock); return NULL; }
关键修复说明
- 独立回复Socket:创建新的socket绑定到2345端口,通过
connect连接客户端地址后发送数据,确保源端口为2345。 - 修正
listen调用:将listen移到循环外,避免重复初始化监听状态。 - 修复发送逻辑:通过指针偏移和累计发送字节数,确保消息完整发送。
- 资源释放:所有socket使用后及时关闭,防止文件句柄泄漏。
内容的提问来源于stack exchange,提问作者hcastro
相关产品推荐
相关产品推荐

