Windows下客户端/服务器Socket程序运行异常:启动后立即退出
问题:Windows下Socket传输程序运行后自动关闭
我使用以下命令编译了客户端和服务器代码:
- 服务器:
gcc server.c -o server.exe -lws2_32 - 客户端:
gcc client.c -o client.exe -lws2_32
代码编译成功生成对应.exe文件,但运行server.exe和client.exe时,程序打开后会突然自动关闭,无法查看完整运行日志。
原因分析
- Winsock库未初始化与清理:Windows平台下使用Winsock API必须先调用
WSAStartup完成库初始化,结束时调用WSACleanup,否则socket()等核心函数会调用失败,直接触发exit(1)导致程序闪退。 - 端口未转换为网络字节序:TCP/IP协议要求端口号使用网络字节序(大端),代码中直接赋值端口号给
sin_port,未用htons()转换,会导致绑定或连接失败。 - 程序执行完毕后无暂停:控制台程序执行完
main()函数后会立即关闭窗口,无法查看输出,需要添加暂停逻辑。 - 代码逻辑缺陷:
- 服务器端
write_file函数中,break后的return永远不会执行;客户端发送完文件后未主动关闭写入端socket,导致服务器recv()一直阻塞,直到连接异常断开。 - 客户端
send_file函数用sizeof(data)发送数据,会把缓冲区空字符一并发送,应使用strlen(data)获取实际读取的文件内容长度。
- 服务器端
修复后的代码
服务器端(server.c)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <winsock2.h> #define SIZE 1024 void write_file(int sockfd){ int n; FILE *fp; char *filename = "file2.txt"; char buffer[SIZE]; fp = fopen(filename, "w"); if(fp==NULL){ perror("[-]Error in creating file."); exit(1); } while(1){ n = recv(sockfd, buffer, SIZE, 0); if(n<=0){ break; } fprintf(fp, "%s", buffer); memset(buffer, 0, SIZE); } fclose(fp); printf("[+]Data written to the text file successfully\n"); } int main (){ WSADATA wsaData; // 初始化Winsock库 if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){ perror("[-]WSAStartup failed"); exit(1); } char *ip = "127.0.0.1"; int port = 8080; int e; int sockfd, new_sock; struct sockaddr_in server_addr, new_addr; int addr_size; char buffer[SIZE]; sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd<0){ perror("[-]Error in socket"); WSACleanup(); exit(1); } printf("[+]Server socket created.\n"); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); // 转换为网络字节序 server_addr.sin_addr.s_addr = inet_addr(ip); e = bind(sockfd,(struct sockaddr*)&server_addr, sizeof(server_addr)); if(e<0){ perror("[-]Error in Binding"); closesocket(sockfd); WSACleanup(); exit(1); } printf("[+]Binding Successful.\n"); e = listen(sockfd, 10); if(e==0){ printf("[+]Listening...\n"); } else{ perror("[-]Error in Listening"); closesocket(sockfd); WSACleanup(); exit(1); } addr_size = sizeof(new_addr); new_sock = accept(sockfd,(struct sockaddr*)&new_addr, &addr_size); if(new_sock < 0){ perror("[-]Error in accept"); closesocket(sockfd); WSACleanup(); exit(1); } printf("[+]Client connected.\n"); write_file(new_sock); closesocket(new_sock); closesocket(sockfd); WSACleanup(); // 添加暂停,防止窗口立即关闭 printf("\nPress Enter to exit..."); getchar(); return 0; }
客户端(client.c)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <winsock2.h> #define SIZE 1024 void send_file(FILE *fp, int sockfd){ char data[SIZE] = {0}; while(fgets(data, SIZE, fp)!=NULL){ // 发送实际读取的内容长度,而非整个缓冲区大小 if(send(sockfd, data, strlen(data), 0)== -1){ perror("[-] Error in sending data"); exit(1); } memset(data, 0, SIZE); } // 关闭socket的写入端,通知服务器文件发送完成 shutdown(sockfd, SD_SEND); } int main(){ WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){ perror("[-]WSAStartup failed"); exit(1); } char *ip = "127.0.0.1"; int port = 8080; int e; int sockfd; struct sockaddr_in server_addr; FILE *fp; char *filename = "file.txt"; sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd<0){ perror("[-]Error in socket"); WSACleanup(); exit(1); } printf("[+]Client socket created.\n"); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); // 转换为网络字节序 server_addr.sin_addr.s_addr = inet_addr(ip); e = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if(e == -1){ perror("[-]Error in Connecting"); closesocket(sockfd); WSACleanup(); exit(1); } printf("[+]Connected to server.\n"); fp = fopen(filename, "r"); if(fp == NULL){ perror("[-]Error in reading file."); closesocket(sockfd); WSACleanup(); exit(1); } send_file(fp,sockfd); fclose(fp); printf("[+] File data sent successfully.\n"); closesocket(sockfd); WSACleanup(); // 添加暂停,防止窗口立即关闭 printf("\nPress Enter to exit..."); getchar(); return 0; }
编译与运行说明
保持原编译命令不变:
- 服务器:
gcc server.c -o server.exe -lws2_32 - 客户端:
gcc client.c -o client.exe -lws2_32
运行时先启动server.exe,待显示"Listening..."后再启动client.exe,程序执行完毕后会等待按下Enter才关闭窗口,可查看完整运行日志。
内容的提问来源于stack exchange,提问作者Chandima Maduwantha
相关产品推荐
相关产品推荐

