#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()
).
На этом этапе вы можете отправить себе однобайтовое сообщение (или что-то более конкретное), чтобы разбудить себя.