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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:57:47