Winsock - How to receive and send data simultaneously?
<p>I'm creating a simple chat client, where clients join the server and send messages to it, which then in turn sends those messages to all the other connected clients.</p>

<p>The issue I have is with figuring out how to have the clients be able to send messages to the server while also being able to simultaneously receive inbound messages from other clients via the server. The problem I run into is that any method I find of taking an input in, always makes the thread hang (as it's waiting for an input from the user).</p>

<p>This is true also for when listening for incoming data, but I've found a way to timeout the wait so I can loop it, and do things before seeing if there is any data needing to be processed again.</p>

<p>My client code: </p>

<pre><code>int main()
{
WSADATA wsaData;

SOCKET ConnectionSocket = INVALID_SOCKET;

addrinfo  *result = NULL;
addrinfo  hints;
addrinfo  *ptr    = NULL;

fd_set    set;

HANDLE    hThread;

string username;

unsigned  threadID;
int       iResult;
int       sent_msg;
int fileD;

char      send_buffer[DEFAULT_BUFLEN];
char      recieve_buffer[DEFAULT_BUFLEN];

bool      connected = true;

int       error_code;                

timeval   timeout_period;

/*
* Initalize WinSock.
*/
if (init_WinSock(wsaData)) { return 1; };

/*
* Zeroize structure.
*/
ZeroMemory(&amp;hints, sizeof(hints));

hints.ai_family   = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

getaddrinfo("192.168.1.77", DEFAULT_PORT, &amp;hints, &amp;result);

ptr = result;

ConnectionSocket = socket(ptr-&gt;ai_family, ptr-&gt;ai_socktype, ptr-&gt;ai_protocol);

iResult = connect(ConnectionSocket, ptr-&gt;ai_addr, ptr-&gt;ai_addrlen);

freeaddrinfo(result);

if (iResult == SOCKET_ERROR) {
    error_code = WSAGetLastError();

    closesocket(ConnectionSocket);

    cout &lt;&lt; "Unable to connect!";
    WSACleanup();
    system("Pause &gt;&gt; null");
    return 1;
}

cout &lt;&lt; "Connected." &lt;&lt; endl;
cout &lt;&lt; "Please choose a username: ";

do {
    cin.getline(send_buffer, (int)strlen(send_buffer));

    if ((int)strlen(send_buffer) &gt; 10) {
        cout &lt;&lt; "Name too long! Choose again: ";
        memset(send_buffer, 0, DEFAULT_BUFLEN);
    }
} while ((int)strlen(send_buffer) &gt; 10);

username = send_buffer;

/*
 * Initial connection. Send ID/username.
 */
send(ConnectionSocket, send_buffer, (int)strlen(send_buffer), 0);

memset(recieve_buffer, 0, DEFAULT_BUFLEN);

while (iResult != SOCKET_ERROR) {
    FD_ZERO(&amp;set); /* clear the set */
    FD_SET(ConnectionSocket, &amp;set);
    FD_SET(0, &amp;set);

    error_code = select(ConnectionSocket + 1, &amp;set, NULL, NULL, NULL);
    error_code = WSAGetLastError();

    if (FD_ISSET(0, &amp;set)) {
        cin.getline(send_buffer, DEFAULT_BUFLEN);

        cout &lt;&lt; username &lt;&lt; ": " &lt;&lt; send_buffer &lt;&lt; endl;

        send(ConnectionSocket, send_buffer, DEFAULT_BUFLEN, 0);

        memset(send_buffer, 0, DEFAULT_BUFLEN);
    } else if (FD_ISSET(ConnectionSocket, &amp;set)) {
        iResult = recv(ConnectionSocket, recieve_buffer, DEFAULT_BUFLEN, 0);
        recieve_buffer[iResult] = '\0';

        cout &lt;&lt; "Placeholder: " &lt;&lt; recieve_buffer &lt;&lt; endl;

    }       
}

closesocket(ConnectionSocket);

cout &lt;&lt; "\n\nDisconnected...";

system("pause &gt;&gt; null");

return 0;
}
</code></pre>

<p>Server code:</p>

<pre><code>unsigned __stdcall handle_client(void *data)
{
    client_socket_data_type client;

    char                    recvbuf[DEFAULT_BUFLEN];

    timeval                 timeout_period;

    fd_set                  set;

    int iResult;

   // mutex                   mtx;

    client = *((client_socket_data_type *)data);

    memset(recvbuf, 0, DEFAULT_BUFLEN);

    timeout_period.tv_sec  = MAX_TIMEOUT;
    timeout_period.tv_usec = 0;

    FD_ZERO(&amp;set); /* clear the set */
    FD_SET(client.client_socket, &amp;set);

    iResult = select(client.client_socket, &amp;set, NULL, NULL, &amp;timeout_period);

    while (iResult != SOCKET_ERROR) {
        if (iResult &gt; 0) {
            recv(client.client_socket, recvbuf, DEFAULT_BUFLEN, 0);

            if (recvbuf != " ") {
                for each (SOCKET connected_clients in client.connected_clients)
                {
                    if (client.client_socket != connected_clients) {
                        send(connected_clients, recvbuf, DEFAULT_BUFLEN, 0);
                        memset(recvbuf, 0, DEFAULT_BUFLEN);
                    }
                }
            }
        }
        iResult = select(client.client_socket, &amp;set, NULL, NULL, &amp;timeout_period);
    } 

    clients--;

    return 0;
}

int main()
{
    WSADATA wsaData;

    SOCKET    listen_socket = INVALID_SOCKET;
    SOCKET    client_socket = INVALID_SOCKET;

    struct addrinfo *result = NULL;
    struct addrinfo  hints;

    client_socket_data_type client;

    HANDLE    hThread;

    unsigned  threadID;

    char recv_buffer[DEFAULT_BUFLEN];

    void *ctx;

    int error_code;
    int iResult;


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

    /*
    * Zeroize structure.
    */
    ZeroMemory(&amp;hints, sizeof(hints));

    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    iResult = getaddrinfo(NULL, DEFAULT_PORT, &amp;hints, &amp;result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    listen_socket = socket(result-&gt;ai_family, result-&gt;ai_socktype, result-&gt;ai_protocol);
    if (listen_socket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

   iResult = bind(listen_socket, result-&gt;ai_addr, (int)result-&gt;ai_addrlen);
   if (iResult == SOCKET_ERROR) {
       printf("bind failed with error: %d\n", WSAGetLastError());
       freeaddrinfo(result);
       closesocket(listen_socket);
       WSACleanup();
       return 1;
   }

    /*
    * Finished setup. Clear structure.
    */
    freeaddrinfo(result);

    /*
    * Listen on port for inbound connections.
    */
    iResult = listen(listen_socket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }

    cout &lt;&lt; "Server initalized successfully. Waiting on client connections. 0/" &lt;&lt; MAX_CLIENTS &lt;&lt; endl;

    memset(recv_buffer, 0, DEFAULT_BUFLEN);

    while (true) {
        while (clients &lt; MAX_CLIENTS) {
            client_socket = SOCKET_ERROR;

            while (client_socket == SOCKET_ERROR) {
                client_socket = accept(listen_socket, NULL, NULL);
            }

            client.client_socket = client_socket;

            clients++;

            cout &lt;&lt; "Client connected. Number of connected clients: " &lt;&lt; clients &lt;&lt; '/' &lt;&lt; MAX_CLIENTS &lt;&lt; endl;

            /*
            * Initial connection. Asking for name.
            */

            recv(client.client_socket, recv_buffer, DEFAULT_BUFLEN, 0);

            cout &lt;&lt; "Debug, name recieved. Name is: " &lt;&lt; recv_buffer &lt;&lt; endl;

            /*
            * Name put inside structure.
            */
            client.client_name = recv_buffer;

            ctx = &amp;client;

            hThread = (HANDLE)_beginthreadex(NULL, 0, &amp;handle_client, ctx, 0, &amp;threadID);

            client.connected_clients.push_back(client.client_socket);

            memset(recv_buffer, 0, DEFAULT_BUFLEN);
        }
    }

    return 0;
}
</code></pre>