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

C语言客户端服务器断开后无限循环问题的解决与规避方案

Fixing Client Infinite Loop on Server Shutdown & Prevention Tips

Hey there, let's break down why your client gets stuck repeating the last message when the server shuts down, and fix this issue once and for all.

What's Causing the Infinite Loop?

Your code has two critical issues leading to this behavior:

  1. Ignoring recv's 0 return value: When a TCP server closes the connection, recv (or recvfrom in your code) returns 0 to signal the connection is terminated. Your current code only handles negative return values (errors) but doesn't break the loop when ret == 0. This means the loop keeps running, and since you never clear the buffer, it keeps printing the last received message over and over.
  2. Mixing TCP and UDP APIs: You're using a TCP socket (SOCK_STREAM) but calling UDP-specific functions (recvfrom/sendto). While these technically work for TCP, they're unnecessary and can lead to confusion. Stick to TCP-native functions like recv and send for stream sockets.

Corrected Client Code

Here's the fixed version with key improvements explained:

#include"stdio.h"
#include"stdlib.h"
#include"sys/types.h"
#include"sys/socket.h"
#include"string.h"
#include"netinet/in.h"
#include"netdb.h"
#include"pthread.h"
#define PORT 4444
#define BUF_SIZE 2000

void * receiveMessage(void * socket) {
 int sockfd, ret;
 char buffer[BUF_SIZE];
 // Safely cast void* back to int* (avoids issues with pointer size mismatches)
 sockfd = *(int*)socket; 
 memset(buffer, 0, BUF_SIZE);
 
 for (;;) {
 // Use recv instead of recvfrom for TCP, leave 1 byte for null terminator
 ret = recv(sockfd, buffer, BUF_SIZE-1, 0); 
 if (ret < 0) {
 printf("Error receiving data!\n");
 break;
 } else if (ret == 0) {
 // Explicitly handle server connection closure
 printf("\nServer disconnected. Exiting client...\n");
 break;
 } else {
 // Null-terminate received data to prevent garbage output
 buffer[ret] = '\0'; 
 printf("server: %s", buffer);
 }
 }
 close(sockfd); // Clean up socket before exiting the thread
 pthread_exit(NULL);
}

int main(int argc, char**argv) {
 struct sockaddr_in addr, cl_addr;
 int sockfd, ret;
 char buffer[BUF_SIZE];
 char * serverAddr;
 pthread_t rThread;

 if (argc > 2) {
 printf("usage: client < ip address >\n");
 exit(1);
 }
 serverAddr = argv[1];

 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 if (sockfd < 0) {
 printf("Error creating socket!\n");
 exit(1);
 }
 printf("Socket created...\n");

 memset(&addr, 0, sizeof(addr));
 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = inet_addr(serverAddr); // Use command-line IP instead of hardcoding
 addr.sin_port = htons(PORT); // Convert port to network byte order (you missed this!)

 ret = connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));
 if (ret < 0) {
 printf("Error connecting to the server!\n");
 exit(1);
 }
 printf("Connected to the server...\n");

 memset(buffer, 0, BUF_SIZE);
 printf("Enter your messages one by one and press return key!\n");

 // Pass sockfd's address to the thread (safer than direct int-to-void* cast)
 ret = pthread_create(&rThread, NULL, receiveMessage, (void *)&sockfd);
 if (ret) {
 printf("ERROR: Return Code from pthread_create() is %d\n", ret);
 exit(1);
 }

 while (fgets(buffer, BUF_SIZE, stdin) != NULL) {
 // Use send instead of sendto for TCP, send only the actual message length
 ret = send(sockfd, buffer, strlen(buffer), 0); 
 if (ret < 0) {
 printf("Error sending data!\n\t-%s", buffer);
 break;
 }
 puts(buffer);
 }

 pthread_join(rThread, NULL); // Wait for receive thread to exit cleanly
 close(sockfd);
 return 0;
}

Additional key fixes:

  • Added htons(PORT) to convert the port to network byte order (a common oversight that can cause connection issues).
  • Replaced the hardcoded server IP with the command-line argument for flexibility.
  • Added pthread_join to ensure the main thread waits for the receive thread to exit before closing the socket.
  • Send only the actual length of the input message instead of the full buffer size, reducing unnecessary data transfer.

How to Avoid This Issue in the Future

  • Handle all socket function return values: For recv, ret < 0 is an error, ret == 0 means the peer closed the connection, and ret > 0 is the number of bytes received. Never ignore any of these cases.
  • Match socket type to API: Use TCP-specific functions (connect, recv, send) for SOCK_STREAM sockets, and UDP-specific functions (bind, recvfrom, sendto) for SOCK_DGRAM sockets.
  • Null-terminate received data: TCP is a byte stream, so received data won't be automatically null-terminated. Always add a \0 to your buffer to avoid garbage characters when printing.
  • Pass thread data safely: Don't cast int directly to void* (size mismatches can happen on 64-bit systems). Instead, pass the address of the integer to the thread.
  • Clean up resources: Always close sockets and wait for threads to exit to avoid resource leaks and undefined behavior.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:43:52