2011-12-15 5 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

+0

Я бы порекомендовал boost asio. – Bashwork

+0

Но в какой момент я бы разблокировал подключенного клиента к новому потоку? Например .. до того, как я установил порт слушателя, то есть каждому клиенту понадобится его собственный порт или после него. И если потом, как я могу заставить класс принимать сообщения асинхронно? Я действительно потерял 100% от того, как это сделать. – natli

ответ

0

При выполнении сокеты, вы в основном имеют один слушатель сокет для всех входящих соединений, а также тройники обработчика для каждого подключенного клиента.

В этом суть. Вам нужен отдельный поток для сокета-слушателя. Когда он получает входящий запрос, он запускает другой поток для сокета-обработчика (который будет создавать и отправлять ответ) и снова начинает прослушиваться (вам нужен цикл).

Я бы определенно использовал потоки вместо разветвления. AFAIK на Windows только cygwin может развиваться, но я бы не использовал cygwin для такой программы.

+0

Есть ли шанс, что вы можете предоставить небольшой пример кода, чтобы я знал, как выглядит сокет-обработчик? Или он уже присутствует в моем коде (сам он не написал большую часть)? – natli

+0

Ваш подход очень низкий. Это намного проще написать на C#, Java, Delphi и т. Д. – kol

+0

Пример Windows (на C): http://www.mycplus.com/source-code/c-source-code/tcp-client-and-server/Автор показывает очень четко, как писать клиент и сервер. Слушание выполняется в основном потоке в цикле, и каждый входящий запрос обрабатывается отдельным потоком. Это для Windows, но автор использует API Berkeley Sockets, который также можно использовать в Linux и Mac. – kol

3

Идея проста, вы просто ждете входящих соединений, а после ее принятия передайте сокет в поток.

Вам необходимо передать новый сокет, возвращенный с accept в новый поток; вы могли каждый раз генерировать новый поток и передавать сокет через аргумент или добавлять сокет в общую очередь, используемую кучей рабочих потоков.

Вот код для простого прокси, который я написал, он использует boost для потоков и простую 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 
    } 
} 

Надежда, что помогает :)

+0

Я начал использовать C-пример kol, связанный с этим, поэтому я не использую это прямо сейчас, но я уверен, что он будет использовать его позже, спасибо! – natli

Смежные вопросы