使用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
相关产品推荐
相关产品推荐

