views:

298

answers:

2

Hey everyone,

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

+1  A: 

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.

Dan Breslau
I want to keep it blocking so I can read the data, but your setsockopt() suggestion worked perfectly! Thanks so much!
RageD
@Dennis M.: Thanks. I'd removed the `setsockopt` suggestion in favor of using `ioctlsocket` instead, but either of them should work. I've edited `setsockopt` back into the answer.
Dan Breslau
A: 

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.

seand
Conversely, multiple send()'s can result in a single recv() as well.
Remy Lebeau - TeamB
good clarification -- there's may not be a one-to-one correspondence between send() and recv(). However most of the time it looks like one send() causes one recv()!. This sometimes confuses people when their app fails under heavy load.
seand