Click here to Skip to main content
16,017,651 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have the code for client in which i am making the socket connection with server but the client socket waits until the server closes the socket and then client closes the socket BUT i want is, that client socket(recv call) should wait for 30second on the socket and if no data comes it should move forward,should not be a BLOCKING call

Code is as follows:-

C++
int __cdecl main(int argc, char **argv) 
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;
    
    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed with error: %d\n", WSAGetLastError());

    } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}
Posted

1 solution

The solution is switching the socket to non-blocking mode and then waiting for the socket with select() until the socket becomes readable. With select() you can setup a timeout and when select() returns you can check whether the reason was a timeout or success/failure. If it was success then read out some bytes from the socket. If the received bytes were not enough for example because you received just one byte then jump back to your select() call and wait again for the socket to become readable but this time you have to calculate the new timeout value from the read operation start time and the current time. (Don't rely on select() to return the elapsed time in its last parameter after a timeout, its platform dependent).
I have a blocking-socket C++ class for myself that has a non-blocking socket handle inside and its methods emulate blocking socket calls using select and every methods allow the use of a timeout/deadline. You can use this select trick for every socket operations. With non-bocking sockets don't forget to check for EWOULDBLOCK error code after operations that would otherwise block.
 
Share this answer
 
v2
Comments
Tarun Batra 12-Sep-12 4:21am    
Thanks for the reply sir,can u share your class if u have no problem regarding sharing
pasztorpisti 12-Sep-12 4:25am    
Sorry, I've replied as if you wanted a timouted connect, now I corrected the solution to describe what you have to do in case of recv(). Unfortunately my code is not public domain but I've described how to do it step by step.
Tarun Batra 12-Sep-12 4:30am    
So according to your solution i have to use select() call after connect() call and before recv() call.Is there any Flag to set the socket in Non Blocking Mode?

pasztorpisti 12-Sep-12 4:32am    
Forget about the connect, I misinterpreted your question and described a non-blocking connect in my first solution. If you want a recv with timout then connect as you did before, switch the socket to nonblocking mode, and then perform your recv as I described then you can switch the socket back to blocking mode. Yes, you are using select to block until your socket has data to read out. If you perform a nonblocking recv call on the socket before it becomes readable then it returns with error and WSAGetLastError() returns EWOULDBLOCK. For this reason first you have to wait for the socket to receive some bytes from the network using the select() call, and you use the recv only after that.
[no name] 12-Sep-12 4:32am    
Suggest you read about ioctlsocket().

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900