3

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;
}
Community
  • 1
  • 1
  • Works for everybody else. Did `shutdown()` return an error? Was it the same `s` in both cases? – user207421 Apr 20 '15 at 01:01
  • @EJP No, `shutdown()` did not return an error. Yes, it is the same `s`. Note that I called `shutdown(s, SD_RECEIVE);` from another thread (not from the thread that is blocking on `recv()`). –  Apr 20 '15 at 01:07
  • So to be clear, `shutdown(s, SD_RECEIVE)` returned zero? And note that it would be impossible to call it from the *same* thread that was blocking on `recv()`. – user207421 Apr 20 '15 at 01:12
  • @EJP Yes, it returned `0`. I can edit my question to post the code if you like. –  Apr 20 '15 at 01:14
  • Yes please,enough to show how `s` is the same too. – user207421 Apr 20 '15 at 01:17
  • WIth that code how can you know that `shutdown()` returned zero? There's a distressing absence of error-checking in this code. You aren't even calling `perror()` as the most basic approach. – user207421 Apr 20 '15 at 01:35
  • 1
    @EJP The `printf("%d", shutdown(s, SD_RECEIVE));` wasn't saved in the source file. It's not like I did not call it before! –  Apr 20 '15 at 01:39
  • shutdown(sd, SHUT_RD) is broken on too many socket implementations, btw. Consider using non-blocking approach or use poll/select with reasonable timeout. – user3125367 Apr 20 '15 at 03:33
  • @user3125367 `SHUT_RD` does not exist on Windows. –  Apr 20 '15 at 03:37
  • @user3125367 Too many socket implementations such as which ones? Facts please, not vague generalizations. – user207421 Apr 20 '15 at 04:05
  • @user4592590 It's a perfectly reasonable question. Thaet `printf()` you now mention isn't present in the code you posted. – user207421 Apr 20 '15 at 04:06
  • @EJP did `shutdown(s, SD_RECEIVE);` exited `recv()` on your machine, or is it broke on Windows or something? –  Apr 20 '15 at 05:22
  • http://stackoverflow.com/questions/8049677/stopping-a-receiver-thread-that-blocks-on-recv thread contains a detailed discussion under accepted answer. Although shutdown(RD) may be widely used by some group to cancel recv calls, there is no evidence in any docs (okay, wsa and posix at least) that it should. SD_RECEIVE is a synonym for SHUT_RD. – user3125367 Apr 20 '15 at 19:09
  • http://stackoverflow.com/questions/18267146/how-to-let-a-thread-which-blocks-on-recv-exit-gracefully good thread too. – user3125367 Apr 20 '15 at 19:26
  • @user4592590 Your question is perfectly legitimate, unfortunately you didn't post the code on the server side. Otherwise, you're rigth: `shutdown` does not always work, but `closesocket` does. – Liviu Jun 21 '15 at 22:48

1 Answers1

2

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Who told you that "input" means "send"? –  Apr 20 '15 at 03:42
  • It does not work if the server doesn't accept input (a client can only listen), and in this case only `closesocket` really works. – Liviu Jun 21 '15 at 22:44
  • As `closesocket` is not really recommended ("A Winsock client must never issue closesocket on s concurrently with another Winsock function call."), the solution for this kind of server is a not blocking socket (`select` + `recv`). – Liviu Jun 21 '15 at 23:10
  • @Liviu You keep talking about `closesocket((`. I don't know why. This post doesn't mention it. The server not accepting Input has nothing to do with it. Either the client is blocked in `recv()` or it isn't, and if it is this will unblock it, and if it isn't it's not an instance of this question. – user207421 Feb 06 '19 at 17:50
  • In the answer: "This will be handled by the server and it will close the socket." The previous comment states the opposite: "The server not accepting Input has nothing to do with it." I am out of this discussion. – Liviu Feb 08 '19 at 08:21