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:
- Ignoring
recv's 0 return value: When a TCP server closes the connection,recv(orrecvfromin 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 whenret == 0. This means the loop keeps running, and since you never clear the buffer, it keeps printing the last received message over and over. - 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 likerecvandsendfor 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_jointo 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 < 0is an error,ret == 0means the peer closed the connection, andret > 0is the number of bytes received. Never ignore any of these cases. - Match socket type to API: Use TCP-specific functions (
connect,recv,send) forSOCK_STREAMsockets, and UDP-specific functions (bind,recvfrom,sendto) forSOCK_DGRAMsockets. - Null-terminate received data: TCP is a byte stream, so received data won't be automatically null-terminated. Always add a
\0to your buffer to avoid garbage characters when printing. - Pass thread data safely: Don't cast
intdirectly tovoid*(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
相关产品推荐
相关产品推荐

