退出阻塞的recv()调用 [英] Exit a blocking recv() call

查看:119
本文介绍了退出阻塞的recv()调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要退出阻塞的recv()电话。在此基础上问题,我应该做到以下几点:

 关机(S,SD_RECEIVE);

但它不工作,的recv()仍然阻挡!


编辑:

这是code我用:

 的#include<&stdio.h中GT;
#包括LT&;&WinSock2.h GT;
#包括LT&;&WINDOWS.H GT;
#包括LT&;&process.h GT;
的#pragma评论(LIB,WS2_32.LIB)unsigned int类型__stdcall recvThread(无效* P)
{
    插座S = *((SOCKET *)p);    字符缓冲区[2048];
    INT大小;    做
    {
        大小= recv的(S,缓冲器,2048,0);        如果(大小大于0)
        {
            的printf(有些数据接收\\ n);
        }
        否则,如果(大小== 0)
        {
            的printf(断开连接\\ n);
        }
        其他
        {
            的printf(断开连接,出现错误\\ n);
        }    }而(大小大于0);    返回0;
}诠释的main()
{
    //初始化Winsock的
    WSADATA WSA;
    调用WSAStartup(MAKEWORD(2,2),&放大器; WSA);    //创建插座
    插座S =插座(AF_INET,SOCK_STREAM,0);    //连接
    有sockaddr_in地址;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(192.168.1.4);
    addr.sin_port = htons(与atoi(12345));
    如果(连接(S,(SOCKADDR *)及地址,的sizeof(地址))== SOCKET_ERROR)
    {
        的printf(无法连接\\ n);
    }
    其他
    {
        的printf(连接\\ n);
    }    //开始的recv()线程
    HANDLE hRecvThread =(HANDLE)_beginthreadex(0,0,recvThread,&放大器; S,0,0);    睡眠(3000);    //退出阻塞的recv()
    关机(S,SD_RECEIVE);    的getchar();
    返回0;
}


解决方案

您需要关闭输入为您链接到的问题提及。
请参阅MSDN上的关机()在这里以及文档:结果
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx

从文档相关报价:


  

关断功能是用来对所有类型的插座,以禁止接收,传输,或两者兼而有之。结果
  如果是如何参数是SD_RECEIVE,随后在插座上的recv函数调用将被禁止。这对较低的协议层没有任何影响。对于TCP套接字,如果仍有数据插座等待接收上排队,或数据到达随后,连接复位,因为数据不能被传递给用户。对于UDP套接字,接收传入数据包和排队。在任何情况下,一个ICMP错误数据包生成。结果
  如果是如何参数是SD_SEND,随后到发送函数调用是不允许的。对于TCP套接字,所有的数据被发送和被接收器确认后一个FIN将被发送。结果
  设置如何SD_BOTH同时禁用发送和如上所述接收。


关键是要发送的FIN。这将通过服务器)来处理,它会关闭套接字,导致你的recv(调用返回。

I want to exit a blocking recv() call. Based on this question, I should do the following:

shutdown(s, SD_RECEIVE);

But it is not working, recv() is still blocking!


Edit:

This is the code I used:

#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;
}

解决方案

You need to shutdown the input as mentioned in the question you linked to. See the documentation for shutdown() on msdn and here as well:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx

Relevant quote from the documentation:

The shutdown function is used on all types of sockets to disable reception, transmission, or both.
If the how parameter is SD_RECEIVE, subsequent calls to the recv function on the socket will be disallowed. This has no effect on the lower protocol layers. For TCP sockets, if there is still data queued on the socket waiting to be received, or data arrives subsequently, the connection is reset, since the data cannot be delivered to the user. For UDP sockets, incoming datagrams are accepted and queued. In no case will an ICMP error packet be generated.
If the how parameter is SD_SEND, subsequent calls to the send function are disallowed. For TCP sockets, a FIN will be sent after all data is sent and acknowledged by the receiver.
Setting how to SD_BOTH disables both sends and receives as described above.

The key is the FIN being sent. This will be handled by the server and it will close the socket, leading to your recv() call returning.

这篇关于退出阻塞的recv()调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆