2011-12-15 275 views
2

我想更改我用来接受无限量客户端的socket class。目前它允许一个客户端,并且一旦该客户端断开服务器退出。让套接字服务器接受多个客户端

#include "stdafx.h" 

#include "mySocket.h" 
#include "myException.h" 
#include "myHostInfo.h" 

void main() 
{ 

#ifdef WINDOWS_XP 
    // Initialize the winsock library 
    WSADATA wsaData; 
    try 
    { 
     if (WSAStartup(0x101, &wsaData)) 
     { 
      myException* initializationException = new myException(0,"Error: calling WSAStartup()"); 
      throw initializationException; 
     } 
    } 
    catch(myException* excp) 
    { 
     excp->response(); 
     delete excp; 
     exit(1); 
    } 
#endif 

    // get local server information 
    myHostInfo uHostAddress; 
    string localHostName = uHostAddress.getHostName(); 
    string localHostAddr = uHostAddress.getHostIPAddress(); 
    cout << "------------------------------------------------------" << endl; 
    cout << " My local host information:" << endl; 
    cout << "  Name: " << localHostName << endl; 
    cout << "  Address: " << localHostAddr << endl; 
    cout << "------------------------------------------------------" << endl; 

    // open socket on the local host 
    myTcpSocket myServer(PORTNUM); 
    cout << myServer; 

    myServer.bindSocket(); 
    cout << endl << "server finishes binding process... " << endl; 

    myServer.listenToClient(); 
    cout << "server is listening to the port ... " << endl; 

    // wait to accept a client connection. 
    // processing is suspended until the client connects 
    cout << "server is waiting for client connecction ... " << endl; 

    myTcpSocket* client; // connection dedicated for client communication 
    string clientHost;  // client name etc. 
    client = myServer.acceptClient(clientHost); 

    cout << endl << "==> A client from [" << clientHost << "] is connected!" << endl << endl; 

    while(1) 
    { 
     //Send message to the client 
     client->sendMessage(std::string("Test")); 

     // receive from the client 
     string clientMessageIn = ""; 
     int numBytes = client->recieveMessage(clientMessageIn); //Get message from client, non-blocking using select() 
     if (numBytes == -99) break; 

     if(clientMessageIn != "") 
     { 
      std::cout << "received: " << clientMessageIn << std::endl; //What did we receive? 

      /* Do somethign with message received here */ 
     } 
    } 

#ifdef WINDOWS_XP 
    // Close the winsock library 

    try 
    { 
     if (WSACleanup()) 
     { 
      myException* cleanupException = new myException(0,"Error: calling WSACleanup()"); 
      throw cleanupException; 
     } 
    } 
    catch(myException* excp) 
    { 
     excp->response(); 
     delete excp; 
     exit(1); 
    } 

#endif 
} 

如何改变main()函数,使其在不断等待新的客户端连接,而一旦他们这样做,为他创造一个新的线程(客户端),或新的处理器插槽(无论这可能是什么)。

我确实发现this线程是提供信息的,但是我缺少实际在上面的代码中实现它所需的套接字知识。

答案指出When doing socket communication, you basically have a single listener socket for all incoming connections, and multiple handler sockets for each connected client.

所以我在我的代码猜;

myTcpSocket myServer(PORTNUM); 
myServer.bindSocket(); 
myServer.listenToClient(); 

将是listener socket

但是哪里/我将如何叉谁是连接开了一个handler socket客户端?

我很抱歉无法在我的部分显示更多的努力,我不喜欢碰到懒惰。但是,在我搜寻的所有时间以及由此导致的反复试验中,我没有太多的展示。

+0

例如,您可以创建新的线程为每个连接的客户端。 – Cyclonecode 2011-12-15 21:00:29

+0

我会推荐加强asio。 – Bashwork 2011-12-15 21:03:27

+0

但是我将在什么时候将连接的客户端分叉到新线程?就像在设置侦听器端口之前,意味着每个客户端都需要自己的端口,或者之后。如果事后,我将如何使这个类异步接受消息?如何做到这一点,我真的百分之百地迷失了方向。 – natli 2011-12-15 21:04:09

回答

0

在做socket通讯,你基本上有一个听众 插座所有传入连接,以及多处理器插座 每个连接的客户端。

这就是要点。您需要一个单独的线程来监听套接字。当它收到一个传入请求时,它会为一个处理程序套接字启动另一个线程(它将创建并发送响应),然后再次开始监听(您需要一个循环)。

我肯定会使用线程而不是分叉。在Windows上的AFAIK只有cygwin能够分叉,但我不会使用cygwin来做这样的程序。

3

这个想法很简单,您只需等待传入连接,并且一旦接受,就将套接字传递给线程。

您需要将从accept返回的新套接字传递给新线程;你可以每次产生一个新的线程并通过参数传递套接字,或者将套接字添加到一堆工作线程使用的共享队列中。

下面是我编写的一个简单代理的一些代码,它使用线程的提升和围绕套接字函数的简单OOP封装。

主线程 - 它创建4个工作线程,这些线程处于空闲状态,并等待信号量被发信号通知 。它推动所有接受的连接到一个全球性的队列:

// Global variables 

const size_t MAX_THREADS = 4; 

queue<Socket> socketBuffer; // Holds new accepted sockets 
boost::mutex queueGuard; // Guards the socketBuffer queue 
semaphore queueIndicator; // Signals a new connection to the worker threads 
bool ctrlc_pressed = false; 

// Inside the main function... 

boost::thread_group threads; 
for(int i = 0; i < MAX_THREADS; i++) 
{ 
    threads.create_thread(boost::bind(&threadHandleRequest, i+1)); 
} 

while(!ctrlc_pressed) 
{ 
    // wait for incoming connections and pass them to the worker threads 
    Socket s_connection = s_server.accept(); 
    if(s_connection.valid()) 
    { 
     boost::unique_lock<boost::mutex> lock(queueGuard); 
     socketBuffer.push(s_connection); 
     queueIndicator.signal(); 
    } 
} 

threads.interrupt_all(); // interrupt the threads (at queueGuard.wait()) 
threads.join_all(); // wait for all threads to finish 

s_server.close(); 

和线程代码:

bool threadHandleRequest(int tid) 
{ 
    while(true) 
    { 
     // wait for a semaphore counter > 0 and automatically decrease the counter 
     try 
     { 
      queueIndicator.wait(); 
     } 
     catch (boost::thread_interrupted) 
     { 
      return false; 
     } 

     boost::unique_lock<boost::mutex> lock(queueGuard); 

     assert(!socketBuffer.empty()); 

     Socket s_client = socketBuffer.front(); 
     socketBuffer.pop(); 

     lock.unlock(); 

     // Do whatever you need to do with the socket here 
    } 
} 

希望帮助:)