Windows平台C++中如何在进程间传递Socket连接?
Windows进程间Socket句柄传递的正确方法
你代码里的核心错误是调用WSADuplicateSocket()时传入了sender自身的进程ID,而不是receiver的进程ID。这个API需要目标进程的ID来生成适配该进程的WSAPROTOCOL_INFO结构,用自己的ID生成的结构在其他进程里无法创建有效的socket句柄,这就是你收到"An operation was attempted on something that is not a socket"错误的原因。
正确操作步骤
- 获取receiver进程的ID:sender需要先拿到receiver的PID,可通过命令行参数传递、共享内存/命名管道等IPC方式传递,或枚举进程根据名称查找。
- sender端正确复制Socket:使用receiver的PID调用
WSADuplicateSocket(),生成仅对receiver有效的WSAPROTOCOL_INFO结构,再确保完整发送给receiver。 - receiver端完整接收并重建Socket:
recv()可能无法一次性接收完整结构,需循环接收直到获取全部字节;重建后建议验证socket有效性。
修正后的Sender端代码
// 先获取receiver进程的PID,替换为实际获取到的receiver PID DWORD receiver_pid = ...; WSAPROTOCOL_INFO protocolInfo; if (WSADuplicateSocket(clientSocket, receiver_pid, &protocolInfo) != 0) { std::cerr << "Failed to duplicate socket handle: " << WSAGetLastError() << std::endl; closesocket(clientSocket); closesocket(listenSocket); WSACleanup(); return 1; } // 确保完整发送WSAPROTOCOL_INFO结构 int total_sent = 0; int remaining = sizeof(protocolInfo); char* buf = (char*)&protocolInfo; while (total_sent < sizeof(protocolInfo)) { int bytes = send(peer_socket, buf + total_sent, remaining, 0); if (bytes == SOCKET_ERROR) { std::cerr << "Send failed: " << WSAGetLastError() << std::endl; closesocket(clientSocket); closesocket(listenSocket); WSACleanup(); return 1; } total_sent += bytes; remaining -= bytes; }
修正后的Receiver端代码
WSAPROTOCOL_INFO protocolInfo; int total_recv = 0; int remaining = sizeof(protocolInfo); char* buf = (char*)&protocolInfo; // 循环接收直到拿到完整的WSAPROTOCOL_INFO结构 while (total_recv < sizeof(protocolInfo)) { int bytes = recv(peer_socket, buf + total_recv, remaining, 0); if (bytes == SOCKET_ERROR || bytes == 0) { std::cerr << "Recv failed: " << WSAGetLastError() << std::endl; closesocket(peer_socket); WSACleanup(); return 1; } total_recv += bytes; remaining -= bytes; } // 重建socket SOCKET childSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, &protocolInfo, 0, 0); if (childSocket == INVALID_SOCKET) { std::cerr << "Failed to create child socket: " << WSAGetLastError() << std::endl; closesocket(peer_socket); WSACleanup(); return 1; } // 可选:验证socket有效性 int optval; int optlen = sizeof(optval); if (getsockopt(childSocket, SOL_SOCKET, SO_TYPE, (char*)&optval, &optlen) == SOCKET_ERROR) { std::cerr << "Invalid socket: " << WSAGetLastError() << std::endl; closesocket(childSocket); closesocket(peer_socket); WSACleanup(); return 1; }
额外注意事项
- 确保sender和receiver进程以相同权限运行,避免UAC权限限制导致socket复制失败。
- 原socket在receiver完成重建并确认可用前不要关闭,否则传递的socket会失效。
- 仅支持流式套接字(SOCK_STREAM)等可复制的socket类型,部分特殊socket可能不支持跨进程传递。
内容的提问来源于stack exchange,提问作者user20208110
相关产品推荐
相关产品推荐

