Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Sockets - Server doesn't accept multiple clients (linux)

Tags:

c++

linux

sockets

I have working server and client code. The server and client can connect and chat with each other correctly. But when I open another client terminal, the client is says Awaiting confirmation from the server and nothing else. Although server and client #1 can still chat.

I searched on multi-threading but the examples or code snippets they show is advanced. Maybe a little explanation or an example will help a lot!

The code below is working. I have a working server but it only accepts one connection. How do I make the server to allow multiple connection? So that I can make the program look like a group chat.

client.cpp (when client #2 connects, the code freezes at line 40)

#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

int main()
{
    char a;
    int client;
    int portNum = 1500;
    int bufsize = 1024;
    char* buffer = new char[bufsize];
    bool isExit = false;
    char* ip = "127.0.0.1";

    struct sockaddr_in direc;

    if ((client = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        cout << "\nError creating socket..." << endl;
        exit(0);
    }

    cout << "\nSocket created successfully..." << endl;
    direc.sin_family = AF_INET;
    direc.sin_port = htons(portNum);
    inet_pton(AF_INET, ip, &direc.sin_addr);

    if (connect(client,(struct sockaddr *)&direc, sizeof(direc)) == 0)
        cout << "Connection to the server " << inet_ntoa(direc.sin_addr) << endl;

    cout << "Awaiting confirmation from the server..." << endl; //line 40
    recv(client, buffer, bufsize, 0);

    cout << "\n=> Enter # to terminate the connection\n" << endl;

    do {
        cout << "Client: ";
        do {
            cin >> buffer;
            send(client, buffer, bufsize, 0);
            if (*buffer == '#') {
                send(client, buffer, bufsize, 0);
                *buffer = '*';
                isExit = true;
            }
        } while (*buffer != 42);

        cout << "Server: ";
        do {
            recv(client, buffer, bufsize, 0);
            cout << buffer << " ";
            if (*buffer == '#') {
                *buffer = '*';
                isExit = true;
            }

        } while (*buffer != 42);
        cout << endl;

    } while (!isExit);
    cout << "=> Connection terminated.\nGoodbye";

    close(client);
    return 0;
}

server.cpp

#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

int main()
{
    int client, server;
    int bufsize = 1024;
    int portNum = 1500;
    bool isExit = false;
    char* buffer = new char[bufsize];

    struct sockaddr_in direc;
    socklen_t tamano;
    pid_t pid;

    if ((client = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        cout << "\nError establishing socket..." << endl;
        exit(1);
    }

    cout << "\nSocket server has been created..." << endl;

    direc.sin_family = AF_INET;
    direc.sin_addr.s_addr = htons(INADDR_ANY);
    direc.sin_port = htons(portNum);

    if ((bind(client, (struct sockaddr*)&direc,sizeof(direc))) < 0) {
        cout << "\nError binding connection..." << endl;
        return -1;
    }

    tamano = sizeof(direc);
    cout << "Looking for clients..." << endl;
    listen(client, 1);

    while ((server = accept(client,(struct sockaddr *)&direc,&tamano)) > 0) {
        strcpy(buffer, "Server connected...\n");
        send(server, buffer, bufsize, 0);
        cout << "Connected with the client, you are good to go..." << endl;
        cout << "Enter # to end the connection\n" << endl;

        cout << "Client: ";
        do {
            recv(server, buffer, bufsize, 0);
            cout << buffer << " ";
            if (*buffer == '#') {
                *buffer = '*';
                isExit = true;
            }
        } while (*buffer != '*');

        do {
            cout << "\nServer: ";
            do {
                cin >> buffer;
                send(server, buffer, bufsize, 0);
                if (*buffer == '#') {
                    send(server, buffer, bufsize, 0);
                    *buffer = '*';
                    isExit = true;
                }
            } while (*buffer != '*');

            cout << "Client: ";
            do {
                recv(server, buffer, bufsize, 0);
                cout << buffer << " ";
                if (*buffer == '#') {
                    *buffer == '*';
                    isExit = true;
                }
            } while (*buffer != '*');
        } while (!isExit);

        cout << "\n=> Connection terminated... " << inet_ntoa(direc.sin_addr);
        close(server);
        cout << "\nGoodbye..." << endl;
        isExit = false;
    }

    close(client);
    return 0;
}

How do I make the server accept multiple connection?

Thanks!

like image 268
Hassan Yousuf Avatar asked Jul 12 '15 20:07

Hassan Yousuf


People also ask

Can multiple clients connect to same server socket?

Irrespective of stateful or stateless protocols, two clients can connect to same server port because for each client we can assign a different socket (as client IP will definitely differ). Same client can also have two sockets connecting to same server port - since such sockets differ by SRC-PORT .

How do you handle multiple clients in socket programming?

A better way to handle multiple clients is by using select() linux command. Select command allows to monitor multiple file descriptors, waiting until one of the file descriptors become active. For example, if there is some data to be read on one of the sockets select will provide that information.

Can TCP handle multiple clients?

The server can receive any number of connections on its single listening port, as long as a different address/port combination is used by each client.

Can a server have multiple sockets?

@premktiw: Yes, multiple client sockets can be bound to the same local IP/port pair at the same time, if they are connected to different server IP/Port pairs so the tuples of local+remote pairs are unique.


2 Answers

In order to properly support multiple connections you should fire up a new thread for each incoming connection. Each new connection is identified by its own unique socket descriptor returned by accept(). A simple example:

while ((accepted = accept(client,(struct sockaddr *)&direc,&tamano)) > 0) {
    /*Create the thread and pass the socket descriptor*/
    if( pthread_create(new_thread, &thread_attributes, &handle_tcp_connection, (void *)accepted) != 0){
      perror("create thread");
      exit(EXIT_FAILURE);
    }
}
like image 106
Manos Avatar answered Oct 15 '22 21:10

Manos


You will need to use select or poll and a state machine pattern to do what you want to do. This means that you will need to process the data as it comes in from whichever client is sending it. Take a look here for a working example.

like image 29
doron Avatar answered Oct 15 '22 23:10

doron