2013-01-29 2 views
1

here에서 여러 클라이언트 (한 클라이언트 당 하나의 스레드)를 처리 할 수있는 작업 서버가 있습니다. 순간 그것은 다음과 같이 작동여러 클라이언트가있는 서버 : 한 클라이언트에서 다른 클라이언트로 메시지를 전달하는 방법

  1. 클라이언트가 서버 측 콘솔에서 서버로 전송 (그리고 표시되는 클라이언트 콘솔에서 서버에
  2. 사용자 유형의 메시지를 연결
  3. 사용자 유형의 메시지를 서버 콘솔에.

그러나 내가하고 싶은 것은 클라이언트 1에서 처리를 위해 서버로가는 메시지를 수신 한 다음 클라이언트 3 (어떤 클라이언트 메시지는 서버에 의해 결정됩니다.)

내 생각에 clientHandleThread을 수정해야하지만, 내가 무엇을해야하는지 모르겠습니다. 또한 현재 스레드와 별도의 스레드에 액세스 할 수 있는지 확실하지 않습니다.

나는 소켓 프로그래밍과 스레드에 익숙하며 배우기가 힘들다. 그래서 어떤 도움을 환영 할 것이다! 입력 한 및 출력을위한 하나 : 당신이 두 개의 큐를 가질 수 있습니다 각 연결을 위해 (! 내가 다른 코드를 첨부해야하는지 알려 주시기 바랍니다)

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; 
} 

답변

0

main()이 포함 된 코드를 부착하고있다. 연결 스레드 (연결 당 하나의 전용 스레드가있는 경우)는 클라이언트에서 입력을 읽고 입력 대기열에 넣습니다. 연결 스레드는 출력 대기열에서 메시지를 가져 와서 연결된 클라이언트로 전송합니다.

그런 다음 서버는 모든 연결 입력 대기열을 통과하고 메시지를 추출한 다음 입력 내용을 결정한 다음 다른 연결의 출력 대기열에 넣을 수있는 또 다른 스레드를 가지고 있습니다.


의사 코드 예제 :이 말은 무엇을

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); 
      } 
     } 
    } 
} 
+0

대기열 가지고 -이에 대한 자세한 내용을 모르고 내 사과. 내 프로그램에 이미 구현 된 큐가 있습니까 (그렇게 생각하지는 않지만 아마도이 오류가있을 수 있습니다)? 대답에서 내 이해는 1/clientHandleThread 아래에 현재 클라이언트에 메시지를 보내고받는 큐를 구현해야합니다. 2/현재 기존 서버 스레드가 하나이며 하나 추가해야합니다. 이 대기열을 처리하는 데 더 많은 시간이 필요합니까? 그리고 나는이 주제에 대해 더 많이 알고 싶습니다. 그러나 이것을 수행하는 좋은 예를 알고 있습니까? (그리고 지금까지 도와 줘서 고맙습니다.) – sccs

+0

@sccs 구현 방법에 대한 간단한 의사 코드 예제가 추가되었습니다. 대기열은 배열 및 목록 뒤에있는 가장 기본적인 데이터 구조 중 하나입니다. –

+0

감사합니다. 나는 이것을 시험해보고 그것이 어떻게 진행되는지 보게 될 것이다. – sccs

관련 문제