C++ Server/Client application
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16

Thread: C++ Server/Client application

  1. #1
    Join Date
    Jan 2009
    Posts
    12

    C++ Server/Client application

    Hello All

    I am working on a server/client application. The client connects to the server and sends some request data to the server, the server receives this data, does some function call, prepare response data and sends the response data back to the client.
    The client then receives the response data.
    The connection is NOT closed then. The client may send another request and so on until the client close the connection.

    Before any connection, the server is in blocking accept() call. If the client connects to the server, so a new thread is created and calls blocking recv() waiting for requests coming from the client.

    The client uses a non blocking recv() with a timeout. (about 2 secs)

    I run a test application that opens two connections with the server, and indefinitely send requests to the server and receive the response.

    It works fine for a while (may be 5 mins, may be 15 mins) but eventually the recv() function of the client times out meaning that it coulding reseive the response data, although the server sends the response back

    I dont know if the data is lost or send function of the server does not really send the data.

    Any suggestions ?

  2. #2
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: C++ Server/Client application

    Well....what does 'WSAGetLastError()' return?
    Ciao, Andreas

    "Software is like sex, it's better when it's free." - Linus Torvalds


    Article(s): Allocators (STL) Function Objects (STL)

  3. #3
    Join Date
    Jan 2009
    Posts
    12

    Re: C++ Server/Client application

    It returns 0. There is no error happened and that is the problem. The data is sent from the server but the client recv() times out without receiving any data.

    What I suspect now is that I am using some thread unsafe thing corrupting the data sent.
    Well my question is: if there is a function that many thread use and takes a pointer to a string as an input, is it thread safe ?

  4. #4
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: C++ Server/Client application

    Quote Originally Posted by theanonymous View Post
    It returns 0. There is no error happened and that is the problem. The data is sent from the server but the client recv() times out without receiving any data.
    The client returns 0? I certainly don't know your code however, do you have error handling for the 'recv()' call? In case it returns 0, the connection has been closed otherwise it has either received something (positive return value) or an error occured ('SOCKET_ERROR' which usually translates to 0xffffffff).

    So how do you determine that it has timed out? If so, this should have been returned by 'WSAGetLastError()' (-> 'WSAETIMEDOUT').

    Quote Originally Posted by theanonymous View Post
    What I suspect now is that I am using some thread unsafe thing corrupting the data sent.

    Well my question is: if there is a function that many thread use and takes a pointer to a string as an input, is it thread safe ?
    That is hard to answer without seeing the function. In general, a function needs to be reentrant to be thread-safe.
    Ciao, Andreas

    "Software is like sex, it's better when it's free." - Linus Torvalds


    Article(s): Allocators (STL) Function Objects (STL)

  5. #5
    Join Date
    Jan 2009
    Posts
    12

    Re: C++ Server/Client application

    Idetect the recv() timeout using the function select(). I put the receiving socket into the read set of the select() and pass the time out to the select() function. Then I check the return value of the select() function. in case there is data to receive, the return value would be 1. If the timeout value has passed, the retuned value is 0.

  6. #6
    Join Date
    Mar 2001
    Posts
    2,364

    Re: C++ Server/Client application

    You need to test and set fdset descriptor sets with the following macros when you use select():

    FD_ZERO()
    FD_SET()
    FD_CLR()
    FD_ISSET();//test the descriptor to see if data is ready.

    From your descriptions you are not doing this.

    HTH,

    PS Here is some code from the free BSD man pages that actually shows how to use it.
    Other OS man systems have some comment about how it may be used but not the actual
    application.

    Code:
         int
         main(int argc, char **argv)
         {
                 fd_set read_set;
                 struct timeval timeout;
                 int ret, fd, i;
    
                 /* file descriptor 1 is stdout */
                 fd = 1;
    
                 /* Wait for ten seconds. */
                 timeout.tv_sec = 10;
                 timeout.tv_usec = 0;
    
                 /* Initialize the read set to null */
                 FD_ZERO(&read_set);
    
                 /* Add file descriptor 1 to read_set */
                 FD_SET(fd, &read_set);
    
                 /*
                  * Check if data is ready to be readen on
                  * file descriptor 1, give up after 10 seconds.
                  */
                 ret = select(fd + 1, &read_set, NULL, NULL, &timeout);
    
                 /*
                  * Returned value is the number of file
                  * descriptors ready for I/O, or -1 on error.
                  */
                 switch (ret) {
                 case -1:
                         err(EXIT_FAILURE, "select() failed");
                         break;
    
                 case 0:
                         printf("Timeout, no data received.\n");
                         break;
    
                 default:
                         printf("Data received on %d file desciptor(s)\n", ret);
    
                         /*
                          * select(2) hands back a file descriptor set where
                          * only descriptors ready for I/O are set. These can
                          * be tested using FD_ISSET
                          */
                         for (i = 0; i <= fd; i++) {
                                 if (FD_ISSET(i, &read_set)) {
                                         printf("Data on file descriptor %d\n", i);
                                         /* Remove the file descriptor from the set */
                                         FD_CLR(fd, &read_set);
                                 }
                         }
                         break;
                 }
    
                 return 0;
         }
    Last edited by ahoodin; January 1st, 2009 at 06:20 PM.
    ahoodin
    To keep the plot moving, that's why.

  7. #7
    Join Date
    Mar 2001
    Posts
    2,364

    Re: C++ Server/Client application

    Was that helpful anonymous poster?

    ahoodin
    To keep the plot moving, that's why.

  8. #8
    Join Date
    Jan 2009
    Posts
    12

    Re: C++ Server/Client application

    Thanks for all who replied.
    Here is my receive function:

    Please review it and tell me if there is something wrong.
    Note that this function is used by many concurrent threads.
    I have a question: Is using select() here safe ? I think that calling select() in a thread may disturb its call in other thread...

    Code:
    long Socket::ReceiveString( std::string* s, 
                               unsigned long ulStringLength, 
                               unsigned long ulTimeout, 
                               TypeSocket type )
    {
        const unsigned long BufferSize = 512;
        char charTemp[BufferSize];
        std::string strReceivedString = "";
        std::string strReceiveError = "Error Receiving Data...";
        // unsigned long Index;
        int rval;
        int ReadSockCount = 0;
        unsigned long quotient  = ulStringLength / BufferSize;
        unsigned long remainder = ulStringLength - ( quotient * BufferSize );
    
    
        fd_set readfds;
        fd_set writefds;
        struct timeval timeout;
        timeout.tv_sec = 0;
        timeout.tv_usec = ulTimeout * 1000;
    
        FD_ZERO(&readfds);
        FD_SET(s_, &readfds);
        //readfds.fd_count = 1;
        //readfds.fd_array[0] = s_;
    
    
        if(type == NonBlockingSocket) 
        {
            u_long arg = 1;
            ioctlsocket(s_, FIONBIO, &arg);
    
            // Begin receive data from server.
            for(unsigned long index = 0; index < quotient; index++)
            {
                // Wait until there is data to be received on the socket, or timeout occurs.
                ReadSockCount = select(0, &readfds, NULL, NULL, &timeout);
    
                // If there is data on the socket, receive it.
                if(ReadSockCount == 1)
                {
                    rval = recv(s_, &charTemp[0], BufferSize, 0);
                    if(rval != BufferSize)
                    {
                        // throw strReceiveError;
                        return -1;
                    }
                }
                // Else if timeout occurred, throw an error.
                else
                {
                    // throw strReceiveError;
                    return -1;
                }
    
                // Append the data received.
                for(unsigned long charIndex = 0; charIndex < BufferSize; charIndex++)
                {
                    strReceivedString += charTemp[charIndex];
                }
            }
    
            // Repeat the previous process on the remainder.
    
            // Wait until there is data to be received on the socket, or timeout occurs.
            ReadSockCount = select(0, &readfds, NULL, NULL, &timeout);
    
            // If there is data on the socket, receive it.
            if(ReadSockCount == 1)
            {
                rval = recv(s_, &charTemp[0], remainder, 0);
                if(rval != remainder)
                {
                    // throw strReceiveError;
                    printf("rval != remainder......\n");
                    return -1;
                }
            }
            // Else if timeout occurred, throw an error.
            else
            {
                int errrrr = WSAGetLastError();
                int jjjjjj = FD_ISSET(s_, &readfds);
                // throw strReceiveError;
                printf("ReadSockCount != 1......\n");
                return -1;
            }
    
            // Append the data received.
            for(unsigned long charIndex = 0; charIndex < remainder; charIndex++)
            {
                strReceivedString += charTemp[charIndex];
            }
        }
        else
        {
            u_long arg = 0;
            ioctlsocket(s_, FIONBIO, &arg);
    
            //for(unsigned long index = 0; index < ulStringLength; index++)
            for(unsigned long index = 0; index < quotient; index++)
            {
                switch( recv(s_, &charTemp[0], BufferSize, 0) ) 
                {
                case 0: // not connected anymore;
                        // ... but last line sent
                        // might not end in \n,
                        // so return ret anyway.
                    s->append(strReceivedString, 0, strReceivedString.length());
                    // throw strReceiveError;
                    return -1;
                case -1:
                    s->erase();
                    //throw strReceiveError;
                    return -1;
                }
    
                // Append the data received.
                for(unsigned long charIndex = 0; charIndex < BufferSize; charIndex++)
                {
                    strReceivedString += charTemp[charIndex];
                }
    
            } // for
    
            // Repeat the previous process on the remainder.
            switch( recv(s_, &charTemp[0], remainder, 0) ) 
            {
            case 0: // not connected anymore;
                    // ... but last line sent
                    // might not end in \n,
                    // so return ret anyway.
                s->append(strReceivedString, 0, strReceivedString.length());
                //throw strReceiveError;
                return -1;
            case -1:
                s->erase();
                //throw strReceiveError;
                return -1;
            }
    
            // Append the data received.
            for(unsigned long charIndex = 0; charIndex < remainder; charIndex++)
            {
                strReceivedString += charTemp[charIndex];
            }
        }
    
        s->append(strReceivedString, 0, strReceivedString.length());
        return 0;
    }
    Last edited by theanonymous; January 3rd, 2009 at 06:08 AM.

  9. #9
    Join Date
    Mar 2001
    Posts
    2,364

    Re: C++ Server/Client application

    Since you are using non-blocking sockets, I might eliminate the timeout by setting it to zero which it looks like you have done.

    If you are calling select() on the same socket in another thread there will probably be trouble. It is probably a bad idea to use the same socket twice for two threads without an overarching design that accounts for it.

    HTH,
    ahoodin
    To keep the plot moving, that's why.

  10. #10
    Join Date
    Jan 2009
    Posts
    12

    Re: C++ Server/Client application

    Each thread uses different socket identifier s_.
    So select() in different threads is called on different sockets.

    I use this receive function in the client in nonblocking mode with a timeout of 2 seconds.
    However, although the server sends the data, the select() times out...
    Last edited by theanonymous; January 3rd, 2009 at 08:05 AM.

  11. #11
    Join Date
    Mar 2001
    Posts
    2,364

    Re: C++ Server/Client application

    select() is used in non-blocking apps all the time.

    EG: http://publib.boulder.ibm.com/infoce...6xnonblock.htm
    ahoodin
    To keep the plot moving, that's why.

  12. #12
    Join Date
    Mar 2001
    Posts
    2,364

    Re: C++ Server/Client application

    I think that the call to select() will just call zero if there is no activity on the socket. This is not an error. It just means there is no work to do (work meaning recv/send). Select will return -1 typically if the sockets are not set up correctly.

    Have a look for yourself:
    http://publib.boulder.ibm.com/infoce...pp_select.html
    Last edited by ahoodin; January 3rd, 2009 at 08:36 AM.
    ahoodin
    To keep the plot moving, that's why.

  13. #13
    Join Date
    Jan 2009
    Posts
    12

    Re: C++ Server/Client application

    I have noticed strange behavior in the code.

    Brief of what server/client do:
    - server runs a blocking recv().
    - when client has a request, it packs the request into a string, sends the length of the string(4 bytes) to the server, then sends the string itself. Then it calls select() (followed by non blocking recv())with timeout waiting for the server to write the response data length to the socket. Then another select() (followed by non blocking recv()) waiting for the server to write the reponse data itself.
    - on the server side, the blocking recv() will return with 4 bytes received, interprets the 4 bytes into a number(length).
    - Then the server calls another blocking recv() to receive number of bytes equal the length.
    - The server then does so processing, prepare response string, sends its length, then sends the response data bytes.
    - The server then goes to the start of the loop again with blocking call of recv() waiting to receive the length of another request.

    ** The problem occurs in one of the select() function calls on the client. It times out.

  14. #14
    Join Date
    Mar 2001
    Posts
    2,364

    Re: C++ Server/Client application

    Timing out should not be a problem. If it does time out just don't do anything with the socket (no sending or recieving) branch over that stuff, loop around again.

    If this doesnt work out why dont you just post your code. Zip it up, including only the .h, .cpp, .vcproj and .sln files. Perhaps it could be fixed up. Running it through
    a debugger will help.

    Note: Actually you don't need to call select() at all, but since you had it in your code I thought I would show you FD_SET etc. You can get away with just sends and recvs unless you need select().
    Last edited by ahoodin; January 3rd, 2009 at 03:02 PM.
    ahoodin
    To keep the plot moving, that's why.

  15. #15
    Join Date
    Jan 2009
    Posts
    12

    Re: C++ Server/Client application

    Thanks for ur replies. I have fount that it is most probably a scheduling problem in the embedded linux i am using.

Page 1 of 2 12 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center