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

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;
}

关键修复说明

  1. 独立回复Socket:创建新的socket绑定到2345端口,通过connect连接客户端地址后发送数据,确保源端口为2345。
  2. 修正listen调用:将listen移到循环外,避免重复初始化监听状态。
  3. 修复发送逻辑:通过指针偏移和累计发送字节数,确保消息完整发送。
  4. 资源释放:所有socket使用后及时关闭,防止文件句柄泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 10:55:04