【问题标题】:Exit a blocking recv() call [duplicate]退出阻塞的recv()调用[重复]
【发布时间】:2015-06-26 13:51:54
【问题描述】:

我想退出阻塞的recv() 呼叫。基于这个question,我应该做以下事情:

shutdown(s, SD_RECEIVE);

但它不起作用,recv() 仍在阻塞!


编辑:

这是我使用的代码:

#include <stdio.h>
#include <WinSock2.h>
#include <Windows.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")

unsigned int __stdcall recvThread(void *p)
{
    SOCKET s = *((SOCKET*)p);

    char buffer[2048];
    int size;

    do
    {
        size = recv(s, buffer, 2048, 0);

        if (size > 0)                               
        {
            printf("Some data received\n");
        }
        else if (size == 0)
        {
            printf("Disconnected\n");
        }
        else
        {
            printf("Disconnected, error occured\n");
        }

    } while (size > 0);

    return 0;
}

int main()
{
    // Initialize Winsock
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);

    // Create socket
    SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

    // Connect
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("192.168.1.4");
    addr.sin_port = htons(atoi("12345"));
    if (connect(s, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
    {
        printf("Unable to connect\n");
    }
    else
    {
        printf("Connected\n");
    }

    // Start recv() thread
    HANDLE hRecvThread = (HANDLE)_beginthreadex(0, 0, recvThread, &s, 0, 0);

    Sleep(3000);

    // Exit blocking recv()
    shutdown(s, SD_RECEIVE);

    getchar();
    return 0;
}

【问题讨论】:

  • 对其他人有效。 shutdown() 是否返回错误?在这两种情况下,s 是否相同?
  • @EJP 否,shutdown() 没有返回错误。是的,它是相同的s。请注意,我从另一个线程(不是从阻塞 recv() 的线程)调用了 shutdown(s, SD_RECEIVE);。
  • 所以要清楚,shutdown(s, SD_RECEIVE) 返回零?请注意,不可能从阻塞recv() 的 same 线程调用它。
  • @EJP 是的,它返回了0。如果您愿意,我可以编辑我的问题以发布代码。
  • @EJP printf("%d", shutdown(s, SD_RECEIVE)); 未保存在源文件中。又不是我之前没叫过!

标签: c sockets winsock


【解决方案1】:

您需要关闭您链接到的问题中提到的输入。 请参阅 msdn 上的 shutdown() 文档以及此处:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx

文档中的相关引用:

关闭功能用于所有类型的套接字以禁用接收、传输或两者。
如果 how 参数是 SD_RECEIVE,则随后对套接字上的 recv 函数的调用将被禁止。这对较低的协议层没有影响。对于 TCP 套接字,如果套接字上仍有等待接收的数据,或者数据随后到达,则重置连接,因为无法将数据传递给用户。对于 UDP 套接字,传入的数据报被接受并排队。在任何情况下都不会生成 ICMP 错误数据包。
如果 how 参数是 SD_SEND,则不允许后续调用 send 函数。对于 TCP 套接字,在所有数据发送完毕并由接收方确认后,将发送一个 FIN。
如上所述,设置如何为 SD_BOTH 会禁用发送和接收。

关键是正在发送的 FIN。这将由服务器处理并关闭套接字,从而导致您的 recv() 调用返回。

【讨论】:

  • 谁告诉你“输入”就是“发送”?
  • 如果服务器不接受输入(客户端只能监听)则不起作用,在这种情况下只有closesocket真正起作用。
  • 因为closesocket 不是真的推荐(“Winsock 客户端绝不能在 s 上同时发出 closesocket 与另一个 Winsock 函数调用。”),这种服务器的解决方案是非阻塞套接字( select + recv)。
  • @Liviu 你一直在谈论closesocket((。我不知道为什么。这个帖子没有提到。服务器不接受 Input 与它无关。客户端在recv() 中被阻止或未被阻止,如果是,则将解除阻止,如果不是,则不是此问题的实例。
  • 在答案中:“这将由服务器处理,它将关闭套接字。”先前的评论则相反:“服务器不接受输入与它无关。”我退出了这个讨论。
猜你喜欢
  • 1970-01-01
  • 2016-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 2013-08-18
  • 1970-01-01
相关资源
最近更新 更多