首页 > 解决方案 > 为什么winsock 不在这里提供WSAESHUTDOWN?

问题描述

最小的,可重现的例子:

#include <cassert>
#include <thread>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")


constexpr int BUF_SZ = 512;
void RecvThread(SOCKET sock)
{
    int iResult = 0;
    char buf[BUF_SZ] = {};

    iResult = recv(sock, buf, BUF_SZ, 0);

    assert(iResult == SOCKET_ERROR);
    assert(WSAGetLastError() == WSAESHUTDOWN);
}


int main()
{
    int iResult;

    WSADATA wsaData;
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    assert(iResult == 0);

    SOCKET sock_1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    assert(sock_1 != INVALID_SOCKET);

    SOCKET sock_2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    assert(sock_2 != INVALID_SOCKET);

    in_addr loopback = {};
    loopback.S_un.S_un_b.s_b1 = 127;
    loopback.S_un.S_un_b.s_b2 = 0;
    loopback.S_un.S_un_b.s_b3 = 0;
    loopback.S_un.S_un_b.s_b4 = 1;

    sockaddr_in addr_1 = {};
    addr_1.sin_family = AF_INET;
    addr_1.sin_port = 51234;
    addr_1.sin_addr = loopback;

    iResult = bind(sock_1, (sockaddr const*)&addr_1, sizeof addr_1);
    assert(iResult != SOCKET_ERROR);

    sockaddr_in addr_2 = {};
    addr_2.sin_family = AF_INET;
    addr_2.sin_port = 51235;
    addr_2.sin_addr = loopback;

    iResult = bind(sock_2, (sockaddr const*)&addr_2, sizeof addr_2);
    assert(iResult != SOCKET_ERROR);

    std::thread t1(RecvThread, sock_1);
    std::thread t2(RecvThread, sock_2);

    iResult = shutdown(sock_1, SD_BOTH);
    assert(iResult != SOCKET_ERROR);
    t1.join(); // after shutdown, join the recv thread

    iResult = shutdown(sock_2, SD_BOTH);
    assert(iResult != SOCKET_ERROR);
    t2.join(); // after shutdown, join the recv thread

    // note: everything works if we delay t1.join() until after shutdown(sock_2)

    iResult = closesocket(sock_1);
    assert(iResult != SOCKET_ERROR);

    iResult = closesocket(sock_2);
    assert(iResult != SOCKET_ERROR);

    iResult = WSACleanup();
    assert(iResult != SOCKET_ERROR);

    return 0;
}

当尝试加入在recv. 如果所有创建的套接字都已交付shutdownWSAESHUTDOWN则程序会干净地退出。

我做错了什么,误解了shutdown应该如何工作,还是这是一个 Windows 错误?

由于这可能是 Windows 错误,因此我使用的是 Microsoft Windows 版本 21H1(OS Build 19043.1165)。

我希望在我使用套接字时收到WSAESHUTDOWNshutdown并且当我shutdown使用两个套接字时会发生这种情况,但是如果我使用shutdown一个套接字然后阻塞线程连接,则程序会挂起。我试图诊断的正是这个问题。

更新:使用的原始问题recv,但显然这是 UDP 套接字的问题,并且缺少关闭错误发生在recvrecvfrom

标签: c++windowssocketsshutdownwinsock2

解决方案


recv()除非您首先调用connect()以将远程对等方与套接字静态关联,否则您不能在 UDP 套接字上使用。否则,recv()无法返回任何数据报,因为它不知道哪些数据报来自所需的对等方,因此它将丢弃所有数据报。

由于您没有调用connect(),因此您应该WSAENOTCONN在两个线程中都遇到错误。

如果您不打算connect()使用套接字,则需要使用recvfrom()


推荐阅读