Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ending "recv()" loop when all information is Read using Winsock

I am having an issue in my recv() loop for winsock. I am trying to terminate the loop when iResult==0, however, the loop only ends when the socket closes. It appears to be hanging at the very last recv() where iResult would equal 0. So any ideas on how to terminate the loop effectively? My ultimate goal (whether iResult == 0 or not; perhaps I am going about this the wrong way) is to stop the loop when all the sent information has been read. Here is the loop.

    do
    {
        iResult = recv(socket, recvbuf, BUFLEN-1, 0);
        if(iResult > 0){
            // Null byte :)
            // Remove that garbage >:(
            recvbuf[iResult] = '\0';
            printf("Recvbuf: %s\n\n\niResult: %d\n",recvbuf,iResult);
            continue; // working properly
        }
        else if(iResult == 0)
            // Connection closed properly
            break;
        else
        {
            printf("ERROR! %ld",WSAGetLastError());
            break;
        }
    } while(iResult > 0);

Like I said, I am receiving all the data, I just cannot exit the loop. The next step would to be write data back to the server, but it hangs here until ping timeout. Socket is SOCK_STREAM and BUFLEN is defined as 0x200

Thanks

like image 640
RageD Avatar asked Jul 27 '10 02:07

RageD


2 Answers

By default, instead of returning 0, recv blocks if there's no data to receive :

If no incoming data is available at the socket, the recv call blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking. In this case, a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK. The select, WSAAsyncSelect, or WSAEventSelect functions can be used to determine when more data arrives.

You can use ioctlsocket to put the socket in non-blocking mode:

u_long iMode = 1;
ioctlsocket(socket, FIONBIO, &iMode);

EDIT: Here's the setsockopt suggestion that I made in an earlier rev, then removed (see comments):

You can use the setsockopt function with the SO_RCVTIMEO option to set the socket to timeout on recv if no data is available.

like image 194
Dan Breslau Avatar answered Oct 04 '22 21:10

Dan Breslau


When you design a TCP communication mechanism you have to define message boundaries. (often \r\n). In of itself, tcp doesn't know about boundaries; you have to do this yourself. The recv() call may not always return on a message boundary. One send() might get split into multiple recv()-s on the other end.

like image 28
seand Avatar answered Oct 04 '22 20:10

seand