Search code examples
c++udpclient-serverchatwinsock

How to make a synchronous chat program to send and receive messages synchronously?


At the moment I am creating a client server console application in c++. With the use of the winsock2.h library and UDP protocol we use the sendto and recvfrom to send messages as strings from the client to the server which will then send the message to a different client, right now if the client1 sends a message to client2, client2 will not receive the message until they attempt to send a message to client1. I am looking to make the program work like an instant messenger, so that when client1 sends a message to client2, client2 will receive it almost instantly without having to send a message first.

Also if client1 were to send a message to client2, client1 would not be able to send another message unless client2 had replied to the first one.

If you need more information or to see some code just ask.

The send code:

while( getline( cin, line ) )
{
    // send a string to the server.
    sendto( hSocket, line.c_str(), line.size(), 0, 
        reinterpret_cast<sockaddr*>( &serverAddress ),
        sizeof( serverAddress ) );

    // recieve the response.
    int n = recvfrom( hSocket, recvLine, MAXLINE, 0, NULL, NULL );
    if( n == -1 )
    {
        cout << "no reply" << endl;
    }
    else
    {
        recvLine[n] = 0;
        string const terminateMsg = "server exit";
        string msg = recvLine;
        if( msg == terminateMsg )
        {
            cout << "Server terminated" << endl;
            break;
        }
        cout << n << ": " << recvLine << endl;
    }
}

Solution

  • right now if the client1 sends a message to client2, client2 will not receive the message until they attempt to send a message to client1.

    you've coded it that way.

    Also if client1 were to send a message to client2, client1 would not be able to send another message unless client2 had replied to the first one.

    Again, you've coded it that way. Your code assumes every sendto() is followed by a recvfrom(). But your question indicates that isn't what you want. I added some comments to your code below

    while( getline( cin, line ) )
    {
        // send a string to the server. <-- will never get here a 2nd time through the loop without recvfrom() returning
        sendto( hSocket, line.c_str(), line.size(), 0, 
            reinterpret_cast<sockaddr*>( &serverAddress ),
            sizeof( serverAddress ) );
    
        // recieve the response. <--- will never get here without getline() returning
        int n = recvfrom( hSocket, recvLine, MAXLINE, 0, NULL, NULL );
        if( n == -1 )
        {
            cout << "no reply" << endl;
        }
        else
        {
            recvLine[n] = 0;
            string const terminateMsg = "server exit";
            string msg = recvLine;
            if( msg == terminateMsg )
            {
                cout << "Server terminated" << endl;
                break;
            }
            cout << n << ": " << recvLine << endl;
        }
    }
    

    I am looking to make the program work like an instant messenger, so that when client1 sends a message to client2, client2 will receive it almost instantly without having to send a message first.

    Use Boost.Asio and asynchronous sockets, the async chat_client example does this very thing perfectly using TCP sockets, it is fairly trivial to modify the example for UDP. The async UDP echo server example may be useful as well. You'll want to use boost::asio::ip::udp::socket::async_recv_from() and boost::asio::ip::udp::socket::async_send_to(). The other BSD socket interfaces have equivalent mappings described in the documentation.