2

I have written a server program in C++ and also a client program in C++. Both are working fine but when if one client is communicating with the server then other client can't get connected to the same server. If suppose when I close the client 1 then also my 2nd client can't connect to the server. I have started my Server with multiple threads to connect to multiple clients but only one client is connecting.

MY server Program:

#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include <thread>
#pragma comment(lib,"ws2_32.lib")

static const int num_of_threads = 2;

void client_disconnected(SOCKET Socket);

void start_server()
{
    WSADATA WsaDat;
    if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
    {
        std::cout<<"WSA Initialization failed!\r\n";
        WSACleanup();
        system("PAUSE");
    }

    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(Socket==INVALID_SOCKET)
    {
        std::cout<<"Socket creation failed.\r\n";
        WSACleanup();
        system("PAUSE");
    }

    SOCKADDR_IN serverInf;
    serverInf.sin_family=AF_INET;
    serverInf.sin_addr.s_addr=INADDR_ANY;
    serverInf.sin_port=htons(8888);

    if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR)
    {
        std::cout<<"Unable to bind socket!\r\n";
        WSACleanup();
        system("PAUSE");
    }

    listen(Socket,3);

    SOCKET TempSock=SOCKET_ERROR;
    while(TempSock==SOCKET_ERROR)
    {
        std::cout<<"Waiting for incoming connections...\r\n";
        Sleep(5000);    
        TempSock=accept(Socket,NULL,NULL);
    }

    // If iMode!=0, non-blocking mode is enabled.
    u_long iMode=1;
    ioctlsocket(Socket,FIONBIO,&iMode);

    Socket=TempSock;
    std::cout<<"Client connected!\r\n\r\n";

    // Main loop
    for(;;)
    {
        int nError=WSAGetLastError();
        if(nError!=WSAEWOULDBLOCK&&nError!=0)
        {
            client_disconnected(Socket);
            break;
        }
        char *szMessage="Welcome to the server!\r\n";
        send(Socket,szMessage,strlen(szMessage),0);
        Sleep(2000);            
    }
}
void client_disconnected(SOCKET Socket)
{
    std::cout<<"Client disconnected!\r\n";

    // Shutdown our socket
    shutdown(Socket,SD_SEND);

    // Close our socket entirely
    closesocket(Socket);

    WSACleanup();
}


int main()
{
   //starting multiple threads for invoking server

    std::thread threads[num_of_threads];
    //This statement will launch multiple threads in loop
    for (int i = 0; i < num_of_threads; ++i) {
        threads[i] = std::thread(start_server);
        Sleep(2000);
    }

    for (int i = 0; i < num_of_threads; ++i) {
        threads[i].join();
    }
    return 0;

}

My Client Program:

#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include "client.h"
#pragma comment(lib,"ws2_32.lib") 


void MultipleClient :: receiveToClient(void*data)
{
    WSADATA WsaDat;
    if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
    {
        std::cout<<"Winsock error - Winsock initialization failed\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // Create our socket

    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(Socket==INVALID_SOCKET)
    {
        std::cout<<"Winsock error - Socket creation Failed!\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // Resolve IP address for hostname
    struct hostent *host;
    if((host=gethostbyname("localhost"))==NULL)
    {
        std::cout<<"Failed to resolve hostname.\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // Setup our socket address structure
    SOCKADDR_IN SockAddr;
    SockAddr.sin_port=htons(8888);
    SockAddr.sin_family=AF_INET;
    SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);

    // Attempt to connect to server
    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0)
    {
        std::cout<<"Failed to establish connection with server\r\n";
        WSACleanup();
        system("PAUSE");

    }

    // If iMode!=0, non-blocking mode is enabled.
    u_long iMode=1;
    ioctlsocket(Socket,FIONBIO,&iMode);

    // Main loop
    for(;;)
    {
        // Display message from server
        char buffer[1000];
        memset(buffer,0,999);
        int inDataLength=recv(Socket,buffer,1000,0);
        std::cout<<buffer;

        //end client when server is disconnected
        int nError=WSAGetLastError();
        if(nError!=WSAEWOULDBLOCK&&nError!=0)
        {
            std::cout<<"Winsock error code: "<<nError<<"\r\n";
            std::cout<<"Server disconnected!\r\n";
            // Shutdown our socket
            shutdown(Socket,SD_SEND);

            // Close our socket entirely
            closesocket(Socket);

            break;
        }
        Sleep(2000);
    }

    WSACleanup();
    system("PAUSE");

}

class Client{
        public:
    static unsigned int __stdcall receiveMessageThread(void *p_this)
        {
            MultipleClient* mc = static_cast<MultipleClient*>(p_this);
            mc-> receiveToClient(p_this); // Non-static member function!
            return 0;
        }
    void startThread()
    {
        HANDLE myhandleA;
            myhandleA = (HANDLE)_beginthreadex(0,0,&Client::receiveMessageThread,this,0, 0);
            WaitForSingleObject(myhandleA, INFINITE);
    }
    };
    int main(void)
    {

        Client *c = new Client;
        c->startThread();

        return 0;
    }

Please help me how to make multiple clients to connect with a single server. A sample code will be very useful(sorry for asking).

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166
hema chandra
  • 402
  • 1
  • 8
  • 29

2 Answers2

2

Your way of distributing work among threads is wrong.

You want one thread to open the listening socket and wait for incoming connections there. Note that you cannot have more than one listening socket per port, so you definitely don't want multiple threads trying to listen on the same port simultaneously.

If a connection comes in, accept will give you a new socket object. You still have the original listening socket, which waits for new connections, but you also have a second socket now with an already established connection to a client.

Now you can split the work: Have one thread go back to calling listen on the original socket and await new connections, while the other thread grabs the new socket and performs the necessary I/O to interact with the client.

In this simple scheme, you will always have one thread per client connection plus an additional thread for the listening socket. Since all of these threads will spent a large amount of time just waiting for network I/O to complete, you can use asynchronous I/O to share the workload between fewer (or even a single) threads, but that is slightly more complex to pull off, so I'd suggest you leave that for a second draft.

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166
0

Using threads. Use one thread for socket server to accept all the Request Connections that coming from clients.

Each thread will have the socket that was assigned by method accept something like this:

Server. This method (run) is running under a new thread. I don't show the method connectionRequest to be practical but keep in mind that this method create the new thread that will attend the Remote End Point.

void SocketServer::run()
{
    int err = 0;

    err = initSocketServer();

    //Fallo el inicio de socket server.
    if (err != NO_ERROR)
    {
        stringstream out;
        out << "There was a problem to bind Native Port: " << _port;
        log->writeError(out.str());
        bKeepRunning = false;
    }
    else
        bKeepRunning = true;

    stringstream out;
    out << "Native Port stablished on port: " << _port;
    log->writeInfo(out.str());


    while (bKeepRunning)
    {
        stringstream out;
        SOCKET socket;

        socket = accept(server, NULL,NULL);

        if (bKeepRunning)
        {
            bool reuseadd = true;
            bool keepAlive = true;

            setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseadd, sizeof(bool));
            setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keepAlive, sizeof(bool));


            //This method will create a new Thread wihc recives the socket.
            connectionRequest(socket);


            // It is ready to accept the nexto connection...
        }
    }

    serverStoped();
}

Attending the Remote End Point. The new thread that has been created by Connection request, must be attendig the Remote End Point to recive a send. Here is a sample on how the execute the other

It isn't my intention to show how to send and recive data by sockets.

void SocketClient::run()
{
    stringstream out;
    bKeepRunning = true;
    bool wasClosed = false;
    int error = 0;
    error = 0;
    do
    {
        if(bSocketSet)
            log->writeDebug(_dlevel,"Socket Previamente asignado, No hay conexion");
        else
            log->writeDebug(_dlevel, "SIN Socket Previamente asignado, Se conectara");

        if(!bSocketSet) //If the socket has not been set
            bConnected = openConnection();

        if (bConnected)
        {

            if (!bSocketSet) //If the socket has not been set
            {
                out.str("");
                out.clear();
                out << "Connected to Server [" << _host << ":" << _port << "]";
                log->writeInfo(out.str());
            }

            //The readMessage will performed a loop to read data an report.
            error = readMessage(&wasClosed);

            if ((error != 0 && bKeepRunning) || wasClosed)
            {
                out.str("");
                out.clear();
                out << "There was an error on reading data. The connection colud be closed.";
                log->writeError(out.str());
                //if(!wasClosed)
                //closeConnection();
                bConnected = false;
            }

        } // if (bConnected) 
        else 
        {
            if (!bSocketSet)
            {
                out.str("");
                out.clear();
                out << "It was not possible to connect to Server [" << _host << ":" << _port << "]";
                log->writeError(out.str());
                waitForResume(15000); //Wait for 15 second to try to reconect
            }
        } //Else Not Connected

    } while (bKeepRunning && !bSocketSet); //do while The socket is not a Socket set by SocketServer

    if (bConnected)
        closeConnection();
}//SocketClient::run()

By each Thread that attend each Remote End Point you can send a recive many data as the protocol sets it but at the end you must close the connection to release the socket to be used as soon as possible by OS.

Jorge Omar Medra
  • 978
  • 1
  • 9
  • 19