Многопоточный клиентский сервер - PullRequest
1 голос
/ 21 октября 2010

Привет, я работаю над написанием заданий многопоточного клиентского сервера.Пока что я сделал, это открыл сокет в порту и разветвил два потока для прослушивания и записи клиенту.Но мне нужно подключить два типа клиентов к серверу и обслуживать их по-разному.Мой вопрос: какой мой лучший подход?

Я обрабатываю соединение в классе, в котором есть бесконечный цикл для принятия соединения.Когда соединение принято, класс создает два потока для чтения и записи клиенту?Теперь, если я хочу обработать другого клиента другого типа, что нам делать?

Нужно ли открывать другой порт?или возможно обслуживание через тот же порт?Может быть, если можно определить тип клиента в сокете, чем я могу обрабатывать сообщения по-разному.

Или вы предлагаете, как это?

  1. Форк два потока для двух типоввходящего соединения клиента и монитора в каждом потоке в другом порту.
  2. когда соединение принимает каждый поток, порождают еще два потока для прослушивания и записи.

, пожалуйста, сделайте предложение.

Ответы [ 3 ]

4 голосов
/ 21 октября 2010

Возможно, вы получите лучший ответ от пользователя Unix, но я предоставлю то, что знаю.

Вашему серверу нужен поток, который открывает «прослушивающий» сокет, который ожидает входящих соединений.Этот поток может быть основным потоком для простоты, но может быть альтернативным потоком, если вы обеспокоены, например, взаимодействием с пользовательским интерфейсом (в Windows это будет проблемой, не уверенной в Unix).Похоже, вы как минимум так далеко.

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

Когда подключается новый клиент, ваш «слушающий» сокет предоставит новый »подключен сокет, который вы передадите другому потоку.На данный момент у вас есть два потока - один, который управляет первым соединением, и другой, который управляет вторым соединением.Что касается розеток, то здесь нет различий между клиентами.У вас просто есть два открытых соединения, по одному с каждым из ваших двух клиентов.

На этом этапе возникает вопрос, что означает «обслуживать их по-другому».Если ожидается, что клиенты будут взаимодействовать с сервером уникальными способами, то это нужно как-то определить.Взаимодействия могут быть определены на основе IP-адреса «клиентского» сокета, который вы можете запросить, но это кажется произвольным и может быть изменено в сети.Он также может основываться на начальном блоке данных, полученных из сокета «клиент», который указывает требуемый тип взаимодействия.В этом случае поток, управляющий «подключенным» сокетом, может прочитать сокет для ожидаемого типа взаимодействия, а затем передать сокет объекту класса, который управляет этим типом взаимодействия.

Надеюсь, это поможет.

1 голос
/ 21 октября 2010

Вы можете обрабатывать чтение-запись по одному клиентскому соединению в одном потоке. Простейшее решение, основанное на многопоточности, будет таким:

// C++ like pseudo-code
while (server_running)
{
    client = server.accept();
    ClientHandlingThread* cth = CreateNewClientHandlingThread(client);
    cth->start();
}

class ClientHandlingThread
{
    void start()
    {
         std::string header = client->read_protocol_header();
         // We get a specific implementation of the ProtocolHandler abstract class
         // from a factory, which create objects by inspecting some protocol header info. 
         ProtocolHandler* handler = ProtocolHandlerFactory.create(header);         
         if (handler)
             handler->read_write(client);
         else
            log("unknown protocol")
    }    
};

Для лучшего масштабирования вы можете использовать пул потоков вместо того, чтобы создавать новый поток для каждого клиента. Существует множество свободных пулов потоков реализаций для C ++ .

while (server_running)
{
    client = server.accept();
    thread_pool->submit(client);
    cth->start();
}

Сервер можно было бы улучшить, используя некую платформу, которая реализует схему реактора . Они используют функции select или poll под капотом. Вы можете использовать эти функции напрямую. Но для производственной системы лучше использовать существующую конструкцию реактора. ACE - один из наиболее широко известных наборов инструментов C ++ для разработки параллельных приложений с высокой степенью масштабируемости.

0 голосов
/ 21 октября 2010

Различные протоколы обычно обслуживаются на разных портах. Однако вы можете обслуживать оба типа клиентов через один и тот же порт, согласовав используемый протокол. Это может быть так же просто, как клиент, отправляющий либо HELO, либо EHLO для запроса того или иного вида услуги.

...