проблема выбора () с push-сервером — c / c

#c #windows #unix #select

#c #Windows #unix #выберите

Вопрос:

Я пишу сервер на C как для систем Windows, так и для Unix.

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

У меня возникли трудности с реализацией решения, которое использует select() функцию в сценарии, описанном выше. Решение, которое я реализовал в настоящее время, меня совсем не убеждает, и я думаю, что его можно реализовать с помощью лучших шаблонов / решений.

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

Это основной цикл select ():

     if((sel_res_ = select(nfds_ 1, amp;read_FDs_, NULL, amp;excep_FDs_, amp;sel_timeout)) > 0){
    if(FD_ISSET(serv_socket, amp;read_FDs_)){
        //we have to handle a newly connection.
        ...
        if(sel_res_ > 1){
            //in addition to the newly connection, there is also some other message incoming on client sockets.
            ...
        }
    }else{
        //we have to handle incoming messages on client sockets
        ...
    }
}
  

Это решение хорошо работает для получения данных и ответа на запросы клиентов в синхронной форме.
Однако сервер также должен иметь возможность отправлять асинхронные данные и отправлять, когда это необходимо, пакеты в push.

Для этого я в настоящее время использую отдельные потоки, которые выполняют непосредственно send() на клиентских сокетах.

Это решение меня не убеждает, и я хотел бы централизовать прием и отправку пакетов в потоке селектора.

Основная трудность заключается в том, что select() по своей природе блокируется, и у меня нет контроля, пока клиент не отправит какой-либо пакет или не сработает тайм-аут. Решение установить очень низкое время ожидания меня не убеждает; Я рассматриваю это как простое решение, которое фактически выполняет активное ожидание, и не только, однако, в худшем случае я бы заплатил цену за время ожидания перед отправкой push-пакета.

Я подумал о более «элегантном» решении; Я думаю, будет работать хорошо, но только для платформы Unix / Linux. Я думал использовать анонимный канал и вставить в select() read_FDs_ дескриптор чтения анонимного канала. Таким образом, когда поток хочет отправить данные в push, он записывает что-то в этот канал, прерывая select() и возвращая управление селектору, который затем может предрасполагать к отправке данных клиенту без значительной потери времени. Я думаю, что это решение, к сожалению, не может быть реализовано в Windows, потому select() что функция в этой системе работает только с fd, которые на самом деле являются сокетами.

Итак, вопрос в следующем: существует ли какое-нибудь хорошо известное решение, которое можно использовать для решения такого сценария (как для Linux, так и для Windows)?

Комментарии:

1. Используйте два потока, один для чтения, а другой для записи.

Ответ №1:

Вы можете создать самостоятельный UDP-сокет, это одинаково хорошо работает в Windows и Linux.

По сути, вы создаете сокет UDP, bind() его на INADDR_LOOPBACK и порт 0, и connect() он сам по себе (с адресом, взятым из getsockname() ).

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