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

C语言TCP Socket回显程序问题:服务器recv()调用失败

问题分析与修复:TCP回显程序服务器recv失败问题

核心错误原因

服务器端误用监听套接字进行数据收发是导致recv失败的根本原因:

  • accept()函数会返回一个新的套接字描述符,这个才是用来和已连接客户端进行数据交互的句柄
  • 原代码中没有保存accept()的返回值,反而用最初创建的监听套接字serverSoc调用recv()/send(),这完全不符合TCP套接字的工作逻辑——监听套接字仅用于接受新连接,不能直接收发数据

其他次要问题

  1. 传递数组地址时多余取址:数组名本身就是首地址,无需加&,否则会传递指针的地址,导致数据读写错误
  2. 未处理字符串结束符:recv()不会自动添加\0,直接用printf("%s")会出现乱码
  3. 客户端发送时用sizeof而非strlen:会把数组中未使用的空字符也发出去,浪费带宽
  4. 客户端逻辑错误:收到服务器消息后直接return -1,导致程序异常退出

修复后的Server.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/ip.h>
#include<string.h>

int main(){
    // 创建监听套接字
    int serverSoc = socket(PF_INET, SOCK_STREAM, 0);
    if (serverSoc < 0) {
        perror("socket creation failed");
        return -1;
    }

    struct sockaddr_in serverInfo;
    serverInfo.sin_family = PF_INET;
    serverInfo.sin_port = htons(8000);
    serverInfo.sin_addr.s_addr = INADDR_ANY; 
    socklen_t addrLen = sizeof(serverInfo);

    // 绑定套接字
    if(bind(serverSoc, (struct sockaddr*)&serverInfo, addrLen) < 0){
        perror("bind failed");
        return -1;
    }

    // 监听连接
    if(listen(serverSoc, 1) < 0){
        perror("listen failed");
        return -1; 
    }

    // 接受客户端连接,保存新的通信套接字
    int clientConn = accept(serverSoc, (struct sockaddr*)&serverInfo, &addrLen);
    if(clientConn < 0){
        perror("accept failed");
        return -1;
    }
    printf("客户端已连接\n");

    char recvBuff[50];
    ssize_t bytesRead = recv(clientConn, recvBuff, sizeof(recvBuff)-1, 0);
    if(bytesRead < 0){
        perror("recv failed");
        return -1;
    }else{
        // 添加字符串结束符,避免乱码
        recvBuff[bytesRead] = '\0';
        printf("收到客户端消息: %s\n", recvBuff); 
    }
     
    char sendBuff[50] = "hello from server";
    ssize_t bytesSent = send(clientConn, sendBuff, strlen(sendBuff), 0);
    if(bytesSent < 0){
        perror("send failed");
        return -1;
    }else{
        printf("已发送消息给客户端,字节数: %zd\n", bytesSent);
    }

    // 关闭套接字
    close(clientConn);
    close(serverSoc);
    return 0;
}

修复后的Client.c

#include<stdio.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>

int main(){
    char clientRecv[50];
    char clientSend[50] = "Hello Server!";
    
    // 创建客户端套接字
    int clientSoc = socket(PF_INET, SOCK_STREAM, 0);
    printf("客户端套接字描述符: %d\n", clientSoc);
    if(clientSoc < 0){
        perror("socket creation failed");
        return -1;
    }

    struct sockaddr_in serverInfo;
    serverInfo.sin_family = PF_INET;
    serverInfo.sin_port = htons(8000);
    // 连接本地服务器,也可替换为具体IP
    serverInfo.sin_addr.s_addr = inet_addr("127.0.0.1");

    // 连接服务器
    if(connect(clientSoc, (struct sockaddr*)&serverInfo, sizeof(serverInfo)) < 0){
        perror("connect failed");
        return -1;
    }
    printf("已连接到服务器\n");

    ssize_t bytesSent = send(clientSoc, clientSend, strlen(clientSend), 0);
    if(bytesSent < 0){
        perror("send failed");
        return -1;
    }
    printf("已发送消息给服务器,字节数: %zd\n", bytesSent);

    ssize_t bytesRead = recv(clientSoc, clientRecv, sizeof(clientRecv)-1, 0);
    if(bytesRead < 0){
        perror("recv failed");
    }else{
        clientRecv[bytesRead] = '\0';
        printf("收到服务器消息: %s\n", clientRecv);
    }

    // 关闭套接字
    close(clientSoc);
    return 0;
}

额外说明

  • 使用perror()替代自定义printf,能更准确地输出系统错误信息,方便调试
  • 所有套接字使用完毕后要调用close()关闭,避免资源泄漏
  • 客户端连接时用inet_addr("127.0.0.1")替代INADDR_ANY,更明确指向本地服务器

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:45:38