1

複数のクライアント(クライアントごとに1つのスレッド)を処理できる稼働中のサーバーがあります-ここから適応します。現時点では、次のように機能します。

  1. クライアントはサーバーに接続します
  2. サーバーに送信される(サーバー側のコンソールに表示される)クライアントコンソールでユーザーがメッセージを入力します。
  3. ユーザーは、同じクライアントに送り返されるサーバーコンソールにメッセージを入力します。

しかし、私がやりたいのは、たとえばクライアント1からメッセージを受信し、それが処理のためにサーバーに送られ、次にクライアント3に転送される場合があります(どのクライアントにメッセージを転送するかはサーバーによって決定されます)。

私の推測では、を変更する必要がありますがclientHandleThread、何をする必要があるのか​​わかりません。また、現在のスレッドとは別のスレッドにアクセスできるかどうかもわかりません。

私はソケットプログラミングとスレッドに非常に慣れていないので、一生懸命勉強しようとしているので、どんな助けでも歓迎します!を含むコードを添付していますmain()(他のコードを添付する必要があるかどうか教えてください!)

myLog winLog;

DWORD WINAPI clientHandleThread(LPVOID threadInfo)
{
    //this structure will contain all the data this callback will work on
    myThreadArgument* clientArgument = (myThreadArgument*)threadInfo;

    //the semamphore to protect the access to the std output
    mySemaphore* coutSemaphore = clientArgument->getCoutSemaphore();

    /*get the client connection: receiving messages from client and
    sending messages to the client will all be done by using
    this client connection*/
    myTcpSocket* clientConnection = clientArgument->getClientConnect();
    string clientName = clientArgument->getHostName();

    //the server is communicating with this client here
    while(1)
    {
        string messageFromClient = "";

        //receive from the client

        int numBytes = clientConnection->receiveMessage(messageFromClient);
        if ( numBytes == -99 ) break;

        //write to the console and the log file, so lock the semaphore
        coutSemaphore->lock();

        cout   << "[RECV fr " << clientName << "]: " << messageFromClient << endl;
        winLog << "[RECV fr " << clientName << "]: " << messageFromClient << endl;

        msgInfo proMsgFrCli = msgClassification(messageFromClient);

        //if the client wants to discount
        if ( messageFromClient.compare("quit") == 0 || messageFromClient.compare("Quit") == 0 )
        {
            coutSemaphore->unlock();
            break;
        }
        else // send to the client
        {
            char messageToClient[MAX_MSG_LEN+1];
            memset(messageToClient,0,sizeof(messageToClient));
            cout << "[SEND to " << clientName << "]: ";
            cin.getline(messageToClient,MAX_MSG_LEN);
            winLog << "[SEND to " << clientName << "]: " << messageToClient << endl;
            clientConnection->sendMessage(string(messageToClient));
            coutSemaphore->unlock();
        }
    }

    // if we reach here, this session with the client is done,
    // so we set the event on this thread to inform the main
    // control that this session is finished
    clientArgument->getExitEvent()->setEvent();
    return 1;
}

DWORD WINAPI serverHandleThread(LPVOID threadInfo) //server thread
{
    //this structure will contain all the data this callback will work on
    myThreadArgument* serverArgument = (myThreadArgument*)threadInfo;

    //the semamphore to protect the access to the std output
    mySemaphore* coutSemaphore = serverArgument->getCoutSemaphore();

    //get the server
    myTcpSocket* myServer = serverArgument->getClientConnect();
    string serverName = serverArgument->getHostName();

    //bind the server to the socket
    myServer->bindSocket();
    cout   << endl << "server finishes binding process... " << endl;
    winLog << endl << "server finishes binding process... " << endl;

    //server starts to wait for client calls
    myServer->listenToClient();
    cout   << "server is waiting for client calls ... " << endl;
    winLog << "server is waiting for client calls ... " << endl;

    //server starts to listen, and generates a thread to handle each client
    myThreadArgument* clientArgument[MAX_NUM_CLIENTS];
    myThread* clientHandle[MAX_NUM_CLIENTS];
    for ( int i = 0; i < MAX_NUM_CLIENTS; i++ )
    {
        clientArgument[i] = NULL;
        clientHandle[i] = NULL;
    }
    int currNumOfClients = 0;
    char buffer [100]; //temp buffer to convert currNumOfClients to char

    while ( 1 )
    {
        //wait to accept a client connection.  
        //processing is suspended until the client connects
        myTcpSocket* client; //connection dedicated for client communication
        string clientName; //client name 
        client = myServer->acceptClient(clientName);    
        clientName = clientName + "-" + itoa(currNumOfClients, buffer, 10);//char(65+currNumOfClients);

        //lock the std out so we can write to the console
        coutSemaphore->lock();
        cout   << endl << endl << "==> a client from [" << clientName << "] is connected!" << endl;
        winLog << endl << "==> a client from [" << clientName << "] is connected!" << endl << endl;

        coutSemaphore->unlock();

        //for this client, generate a thread to handle it
        if ( currNumOfClients < MAX_NUM_CLIENTS-1 )
        {
            clientArgument[currNumOfClients] = new myThreadArgument(client,coutSemaphore,clientName);
            clientHandle[currNumOfClients] = new myThread(clientHandleThread,(void*)clientArgument[currNumOfClients]);
            serverArgument->addClientArgument(clientArgument[currNumOfClients]);
            clientHandle[currNumOfClients]->execute();
            currNumOfClients++;
        }
    }

    return 1;
}

int main()
{
    /*build a semaphore so we can synchronize the access to std cout
    also includes the log file*/
    mySemaphore coutSemaphore(string(""),1);

    //initialize the winsock library
    myTcpSocket::initialize();

    /*create the server: local host will be used as the server, let us 
    first use myHostInfo class to show the name and IP address 
    of the local host*/
    winLog << endl;
    winLog << "retrieve the local host name and address:" << endl;

    myHostInfo serverInfo;
    string serverName = serverInfo.getHostName();
    string serverIPAddress = serverInfo.getHostIPAddress();
    cout << "my localhost (server) information:" << endl;
    cout << "   name:    " << serverName << endl;
    cout << "   address: " << serverIPAddress << endl;
    winLog << "     ==> name: " << serverName << endl;
    winLog << "     ==> address: " << serverIPAddress << endl;

    //open socket on the local host(server) and show its configuration
    myTcpSocket myServer(PORTNUM);
    cout   << myServer;
    winLog << myServer;

    //read connectivityFile
    neighbourInfo = connFrFile(numberOfFiles, intBtwnChange);
    //read routingFile
    nextHopInfo = routFrFile(numberOfFiles, intBtwnChange);

    /*create a thread to implement server process: listening to the socket,
    accepting client calls and communicating with clients. This will free the 
    main control (see below) to do other process*/
    myThreadArgument* serverArgument = new myThreadArgument(&myServer,&coutSemaphore,serverName);
    myThread* serverThread = new myThread(serverHandleThread,(void*)serverArgument);
    serverThread->execute();

    // main control: since the serverThread is handling the server functions,
    // this main control is free to do other things.
    while ( 1 )
    {
        /*do whatever you need to do here, I am using Sleep(x) 
        to make a little delay, pretending to be the other 
        possible processings*/
        Sleep(50000);

        //report the server status
        coutSemaphore.lock();
        cout   << endl << "-----------------------------------------------------------------" << endl;
        winLog << endl << "-----------------------------------------------------------------" << endl;
        cout   << "server (name:" << serverName << ") status report:" << endl;
        winLog << "server (name:" << serverName << ") status report:" << endl;
        cout   << "   the following clients have successfully connected with server: " << endl;
        winLog << "   the following clients have successfully connected with server: " << endl;
        for ( int i = 0; i < MAX_NUM_CLIENTS; i ++ )
        {
            myThreadArgument* clientInfo = serverArgument->getClientArgument(i);
            if ( clientInfo ) 
            {
                cout   << "         " << clientInfo->getHostName() << endl;
                winLog << "         " << clientInfo->getHostName() << endl;
            }
        }
        cout   << "   the following clients have shutdown the connection: " << endl;
        winLog << "   the following clients have shutdown the connection: " << endl;
        for ( int i = 0; i < MAX_NUM_CLIENTS; i ++ )
        {
            myThreadArgument* clientInfo = serverArgument->getClientArgument(i);
            if ( clientInfo && clientInfo->getExitEvent()->waitForEvent(0) )
            {
                clientInfo->setSignalToEnd(true);
                cout   << "         " << clientInfo->getHostName() << endl;
                winLog << "         " << clientInfo->getHostName() << endl;
            }
        }
        cout   << "-----------------------------------------------------------------" << endl << endl;
        winLog << "-----------------------------------------------------------------" << endl << endl;
        coutSemaphore.unlock();
    }

    return 1;
}
4

1 に答える 1

0

接続ごとに、入力用と出力用の 2 つのキューを持つことができます。接続スレッド (接続ごとに 1 つの専用スレッドがある場合) は、クライアントから入力を読み取り、それを入力キューに入れます。また、接続スレッドは出力キューからメッセージをフェッチし、接続されたクライアントに送信します。

次に、サーバーには別のスレッドがあり、すべての接続入力キューを通過し、メッセージを抽出し、入力をどうするかを決定し、場合によってはそれを他の接続の出力キューに入れます。


擬似コードの例:

struct message_struct
{
    int source;       // Source where the message came from
    int destination;  // Destination client to send message on to
}

void client_thread()
{
    while (!exit_thread)
    {
        if (is_there_anything_to_recv())
        {
            // Receive and parse a message from the client
            message = receive();

            // Add to the threads input queue
            add_to_queue(input_queue, message);
        }

        // As long as there are messages in the output queue
        while (!queue_is_empty(output_queue))
        {
            // Remove one message from the queue
            message = remove_from_queue(output_queue);

            // And send it to the connected client
            send(message);
        }
    }
}

void server_thread()
{
    while (!exit_thread)
    {
        // Check for new connections
        // ...

        // Assuming the threads are on array (or array-like structure)
        for (i = 0; i < number_of_client_threads; i++)
        {
            // While the current threads (`i`)  input queue is not empty
            while (!queue_is_empty(client_threads[i].input_queue))
            {
                // Remove the message from the threads input queue
                message = remove_from_queue(client_threads[i].input_queue);

                // And add it to the destinations output queue
                add_to_queue(client_threads[message.destination].output_queue);
            }
        }
    }
}
于 2013-01-29T08:05:44.977 に答える