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

使用TCP Socket向服务器发送消息时接收失败的问题排查

问题:TCP Socket连接后服务器立即接收失败,无法正常等待客户端消息

我尝试通过TCP Socket向服务器发送消息,但建立连接后服务器立即接收失败,似乎服务器并未等待用户输入消息。服务器本应持续处于while循环中,永久等待客户端连接并打印其发送的消息,目前无法定位问题所在。

服务器代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

#define PORT 4000
#define WORD_SIZE 256
#define USER_SOCKETS 2
#define MAX_USERS 10

int receiveMessage(int socket, char message[])
{
    int bytesReceived;
    while (1)
    {
        bytesReceived = recv(socket, message, WORD_SIZE, 0);
        if (bytesReceived < 0)
            return -1;

        if (bytesReceived == 0)
            return 0;

    }
}

int main(int argc, char *argv[])
{
    int serverSockfd;
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;

    if ((serverSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        printf("Error creating the socket.\n");

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(serv_addr.sin_zero), 8);

    if (bind(serverSockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("Error binding the socket..\n");
        return -1;
    }

    if (listen(serverSockfd, 5) < 0)
    {
        printf("Error on listening.\n");
        return -1;
    }

    int newSockfd;
    while (1) 
    {
        if (newSockfd = accept(serverSockfd, (struct sockaddr *)&cli_addr, &clilen) < 0)
        {
            printf("Error on accept a new client.\n");
            continue;
        }

        char username[WORD_SIZE];
        if (receiveMessage(newSockfd, username) < 0)
        {
            printf("Error receiving message.\n");
            close(newSockfd);
        }

        printf("Message: %s\n", username);
        close(newSockfd);
    }

    return 0;
}

客户端代码

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

#define PORT 4000

int main(int argc, char * argv[]) {
    int sockfd, n;
    struct sockaddr_in serv_addr;
    struct hostent * server;

    char buffer[256];
    if (argc < 2) {
        fprintf(stderr, "usage %s hostname\n", argv[0]);
        exit(0);
    }

    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr, "ERROR, no such host\n");
        exit(0);
    }

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        printf("ERROR opening socket\n");

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr = *((struct in_addr *) server->h_addr);
    bzero( & (serv_addr.sin_zero), 8);

    if (connect(sockfd, (struct sockaddr *) & serv_addr, sizeof(serv_addr)) < 0)
        printf("ERROR connecting\n");

    printf("Enter the message: ");
    bzero(buffer, 256);
    fgets(buffer, 256, stdin);

    /* write in the socket */
    n = write(sockfd, buffer, strlen(buffer));
    if (n < 0)
        printf("ERROR writing to socket\n");

    bzero(buffer, 256);

    printf("%s\n", buffer);

    close(sockfd);
    return 0;
}

问题分析与修复

1. accept 语句的运算符优先级错误

服务器代码中 if (newSockfd = accept(...) < 0) 存在运算符优先级问题:< 的优先级高于 =,导致 newSockfd 被赋值的是 accept(...) < 0 的布尔结果(0 或 1),而非 accept 返回的套接字描述符。这会导致后续使用 newSockfd 进行 recv 操作时完全错误。

修复: 给赋值表达式加括号,确保先完成赋值再做比较:

if ((newSockfd = accept(serverSockfd, (struct sockaddr *)&cli_addr, &clilen)) < 0)

2. receiveMessage 函数逻辑错误

原函数的 while 循环会持续调用 recv,但既没有处理接收到的数据,也没有添加字符串结束符 \0,而且客户端仅发送一次消息就关闭连接,函数会在 bytesReceived == 0 时返回,此时 message 可能没有有效结束符,导致 printf 输出乱码或未定义行为。同时,循环反复覆盖 message 数组,无法保留完整数据。

修复: 修改函数为单次接收并添加结束符(因为客户端只发一次消息):

int receiveMessage(int socket, char message[], int maxSize)
{
    int bytesReceived = recv(socket, message, maxSize - 1, 0); // 预留一个字节放\0
    if (bytesReceived < 0)
        return -1;
    if (bytesReceived == 0)
        return 0;
    message[bytesReceived] = '\0'; // 添加字符串结束符,确保printf正常输出
    return bytesReceived;
}

调用时传入缓冲区大小:

if (receiveMessage(newSockfd, username, WORD_SIZE) <= 0)

3. 其他细节修复

  • 服务器创建套接字失败后,应直接退出程序,避免后续无效操作:
if ((serverSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
    printf("Error creating the socket.\n");
    exit(EXIT_FAILURE);
}
  • 客户端中 bzero(buffer, 256); 和 printf("%s\n", buffer); 是多余的,因为此时缓冲区已被清空,输出为空,可以删除这两行。

修复后的服务器代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

#define PORT 4000
#define WORD_SIZE 256
#define USER_SOCKETS 2
#define MAX_USERS 10

int receiveMessage(int socket, char message[], int maxSize)
{
    int bytesReceived = recv(socket, message, maxSize - 1, 0);
    if (bytesReceived < 0)
        return -1;
    if (bytesReceived == 0)
        return 0;
    message[bytesReceived] = '\0';
    return bytesReceived;
}

int main(int argc, char *argv[])
{
    int serverSockfd;
    socklen_t clilen;
    struct sockaddr_in serv_addr, cli_addr;

    if ((serverSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("Error creating the socket.\n");
        exit(EXIT_FAILURE);
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(serv_addr.sin_zero), 8);

    if (bind(serverSockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("Error binding the socket..\n");
        return -1;
    }

    if (listen(serverSockfd, 5) < 0)
    {
        printf("Error on listening.\n");
        return -1;
    }

    int newSockfd;
    while (1) 
    {
        if ((newSockfd = accept(serverSockfd, (struct sockaddr *)&cli_addr, &clilen)) < 0)
        {
            printf("Error on accept a new client.\n");
            continue;
        }

        char username[WORD_SIZE];
        int recvResult = receiveMessage(newSockfd, username, WORD_SIZE);
        if (recvResult < 0)
        {
            printf("Error receiving message.\n");
            close(newSockfd);
            continue;
        }
        else if (recvResult == 0)
        {
            printf("Client closed connection without sending data.\n");
            close(newSockfd);
            continue;
        }

        printf("Message: %s", username); // fgets会保留换行符,不用再加\n
        close(newSockfd);
    }

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 20:15:51