C#客户端连接C++服务端停滞,连接C#服务端正常
问题分析与解决方案
你遇到的问题核心在于C++服务端的Socket处理逻辑存在严重错误,导致客户端连接后服务端无法正常处理请求,进而让C#客户端陷入停滞。
核心问题点:
- 重复调用
accept():服务端在第一次调用accept()获取到客户端连接后,没有处理这个连接,反而立刻再次调用accept(),这会让服务端阻塞在第二次accept()调用上,等待新的客户端连接,而已经连接的C#客户端的请求完全被忽略。 - 缺少关键步骤的错误检查:
bind()和listen()调用没有做错误判断,万一这两步失败,服务端也不会给出提示,可能隐藏潜在问题。 - 连接后直接清理WSA资源:在第二次
accept()后直接调用WSACleanup(),即使有客户端连接,也会立刻释放Socket资源,导致连接中断。 - 无客户端数据交互逻辑:服务端完全没有编写接收客户端数据、返回响应的代码,C#客户端发送数据后一直在等待服务端回复,自然会停滞。
修正后的C++服务端代码
#include <winsock2.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA wsaData; struct sockaddr_in address_of_server; struct sockaddr_in address_of_client; int size_of_address_of_client = sizeof(address_of_client); // 初始化WSA if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("winsock initialization failure\n"); return 1; } printf("winsock initialization success\n"); // 创建服务端Socket SOCKET socket_of_server = socket(AF_INET, SOCK_STREAM, 0); if (socket_of_server == INVALID_SOCKET) { printf("creating socket failure, error: %d\n", WSAGetLastError()); WSACleanup(); return 1; } printf("creating socket success\n"); // 配置服务端地址 memset(&address_of_server, 0, sizeof(address_of_server)); address_of_server.sin_family = AF_INET; address_of_server.sin_addr.s_addr = htonl(INADDR_ANY); address_of_server.sin_port = htons(8888); // 绑定Socket到地址 if (bind(socket_of_server, (struct sockaddr*)&address_of_server, sizeof(address_of_server)) == SOCKET_ERROR) { printf("bind failed with error: %d\n", WSAGetLastError()); closesocket(socket_of_server); WSACleanup(); return 1; } printf("bind success\n"); // 开始监听连接 if (listen(socket_of_server, 5) == SOCKET_ERROR) { printf("listen failed with error: %d\n", WSAGetLastError()); closesocket(socket_of_server); WSACleanup(); return 1; } printf("listening on port 8888...\n"); // 接受客户端连接(单客户端场景只需要一次调用) SOCKET clientSocket = accept(socket_of_server, (struct sockaddr*)&address_of_client, &size_of_address_of_client); if (clientSocket == INVALID_SOCKET) { printf("accept failed with error: %d\n", WSAGetLastError()); closesocket(socket_of_server); WSACleanup(); return 1; } printf("client connected from %s:%d\n", inet_ntoa(address_of_client.sin_addr), ntohs(address_of_client.sin_port)); // 处理客户端数据交互 char recvBuffer[1024] = {0}; int recvBytes = recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0); if (recvBytes > 0) { printf("received data from client: %s\n", recvBuffer); // 准备返回给客户端的响应(对应C#客户端要读取的5个int) int responseData[5] = {100, 200, 300, 400, 500}; send(clientSocket, (char*)responseData, sizeof(responseData), 0); printf("sent response to client\n"); } else if (recvBytes == 0) { printf("client disconnected\n"); } else { printf("recv failed with error: %d\n", WSAGetLastError()); } // 按顺序清理资源 closesocket(clientSocket); closesocket(socket_of_server); WSACleanup(); return 0; }
对C#客户端的优化建议
你的C#客户端在Data()方法中读取数据时,直接使用ReceiveBufferSize作为读取长度可能会导致问题,因为ReceiveBufferSize是Socket的缓冲区大小,不一定等于实际收到的数据长度。建议调整为:
void Data() { MainWindow mw = (MainWindow)Application.Current.MainWindow; NetworkStream serverStream = mw.clientSocket.GetStream(); // 发送数据 byte[] outStream = System.Text.Encoding.ASCII.GetBytes(A1G1.Text + "$"); serverStream.Write(outStream, 0, outStream.Length); serverStream.Flush(); // 读取响应:因为要读取5个int,直接分配对应大小的缓冲区 byte[] inStream = new byte[sizeof(int) * 5]; int bytesRead = serverStream.Read(inStream, 0, inStream.Length); if (bytesRead == sizeof(int)*5) { using (System.IO.MemoryStream ms = new System.IO.MemoryStream(inStream)) using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) { int[] inComingData = new int[5]; for (int i = 0; i < 5; i++) { inComingData[i] = br.ReadInt32(); Debug.WriteLine(inComingData[i].ToString()); if (i == 0) { A1G1Text.Text = inComingData[0].ToString(); } } } } else { Debug.WriteLine("Received incomplete data from server"); } }
原代码卡住的根本原因
- C++服务端第一次
accept()成功获取到C#客户端的连接后,没有处理这个连接,立刻又调用了第二次accept(),导致服务端一直等待第二个客户端连接,完全忽略了已经连接的第一个客户端。 - C#客户端成功连接后发送了数据,但服务端没有接收和处理,自然不会返回响应,最终让C#客户端卡在
serverStream.Read()调用上,一直等待服务端的回复。
内容的提问来源于stack exchange,提问作者shakeel
相关产品推荐
相关产品推荐

