0

My goal is to create a user-server connection. Most importantly I'm not willing to use threads. For now, I want it to work as a simple chat. I believe The issue is that It goes from one user to another in a loop waiting for their getline input, so technically only one user can send a message at a time. What I wish is that my code could handle multiple messages from one user continuously, not having to wait for all other users to send a message That's the running loop inside the server:

while (running)
{
    fd_set copy = master;

    // See who's talking to us
    int socketCount = select(0, &copy, nullptr, nullptr, nullptr);

    // Loop through all the current connections / potential connect
    for (int i = 0; i < socketCount; i++)
    {
        // Makes things easy for us doing this assignment
        SOCKET sock = copy.fd_array[i];

        // Is it an inbound communication?
        if (sock == listening)
        {
            // Accept a new connection
            sockaddr_in client;
            int clientSize = sizeof(client);
            SOCKET clientsocket = accept(listening, (sockaddr*)&client, &clientSize);

            // Add the new connection to the list of connected clients
            FD_SET(clientsocket, &master);

            // Send a welcome message to the connected client
            string welcomeMsg = "Welcome to the Awesome Chat Server!\r\n";
            send(clientsocket, welcomeMsg.c_str(), welcomeMsg.size() + 1, 0);
        }
        else // It's an inbound message
        {
            char buf[4096];
            ZeroMemory(buf, 4096);

            // Receive message
            int bytesIn = recv(sock, buf, 4096, 0);
            if (bytesIn <= 0)
            {
                // Drop the client
                closesocket(sock);
                FD_CLR(sock, &master);
            }
            else
            {
                
                // Send message to other clients, and definiately NOT the listening socket

                for (int i = 0; i < master.fd_count; i++)
                {
                    SOCKET outSock = master.fd_array[i];
                    if (outSock != listening && outSock != sock)
                    {
                        ostringstream ss;
                        ss << "SOCKET #" << sock << ": " << buf << "\r\n";
                        string strOut = ss.str();

                        send(outSock, strOut.c_str(), strOut.size() + 1, 0);
                    }
                }
            }
        }
    }
}

I belive this code should work, the issue is in my client code:

    char buf[4096];
     string userInput;

    do
    {
        // Prompt the user for some text
        cout << "> ";
        getline(cin, userInput); //THATS THE ISSUE, IT WAITS FOR GETLINE
        if (userInput.size() > 0)       // Make sure the user has typed in something
        {
            // Send the text
            int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
            if (sendResult != SOCKET_ERROR)
            {
                // Wait for response
                ZeroMemory(buf, 4096);
                int bytesReceived = recv(sock, buf, 4096, 0);
                if (bytesReceived > 0)
                {
                    // Echo response to console
                    cout << "SERVER> " << string(buf, 0, bytesReceived) << endl;
                }
            }
        }

    } while (userInput.size() > 0);

My question is if its really caused by getline and if so, how can it be fixed?

Michał Turek
  • 701
  • 3
  • 21
  • Does your client program need to run under Windows? (I ask because afaict Windows does not support non-blocking reads from stdin; the best you can do is fake it with a dedicated thread that does blocking reads from stdin and forwards the data to a non-blocking pipe or socket for the rest of the program to read) – Jeremy Friesner Apr 24 '22 at 19:43

1 Answers1

1

The answer to your question is "yes," but with a big proviso: a properly designed server shouldn't care what the client is doing. You might want to look into select() or, if you anticipate a large user community, poll(). You don't want a multi-user server to depend on/wait for a single client.

mzimmers
  • 857
  • 7
  • 17
  • I used select() indeed, however it does not solve the problem of waiting for user input. Because my main thread will wait for user input from getline and I was wondering if there is a way to avoid this issue. – Michał Turek Apr 25 '22 at 15:20
  • I guess I don't fully understand the problem. The getline() call is in the client; this shouldn't affect your server. But, maybe this will help: https://stackoverflow.com/questions/15524122/how-to-implement-timeout-for-getline – mzimmers Apr 25 '22 at 16:58