Использование accept () и select () одновременно? - PullRequest
20 голосов
/ 10 августа 2010

У меня есть программа сетевого сервера, управляемая событиями.Эта программа принимает соединения от других процессов на других хостах.На одном и том же удаленном IP-адресе может быть много кратковременных соединений из разных портов.

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

Я хочу устранить накладные расходы на установку и разрыв соединений, кэшируя FD с открытым сокетом.Со стороны отправителя это просто - я просто не закрываю соединения и держу их рядом.

Со стороны получателя это немного сложнее.Я знаю, что могу хранить FD, возвращенный accept() в структуре, и прослушивать сообщения через все такие сокеты, используя poll() или select(), но я хочу одновременно и прослушивать новые соединения через accept() и прослушивание всех кэшированных соединений.

Если я использую два потока, один на poll() и один на accept(), то при возврате вызова accept() (открывается новое соединение),Я должен разбудить другой поток, ожидающий старого набора соединений.Я знаю, что могу сделать это с сигналом и pselect(), но весь этот беспорядок кажется слишком большой работой для чего-то такого простого.

Существует ли метод вызова или превосходящая методика, которая позволит мне одновременно обрабатывать новые соединенияоткрывается и данные отправляются по старым соединениям?

Ответы [ 3 ]

23 голосов
/ 10 августа 2010

В прошлый раз, когда я проверял, вы можете просто listen на сокете, а затем select или poll, чтобы увидеть, установилось ли соединение. Если это так, accept it;он не будет блокироваться (но вы , возможно, захотите действительно должны установить O_NONBLOCK просто для уверенности)

5 голосов
/ 31 октября 2012

Вы можете использовать прослушивание, затем использовать выбор или опрос, а затем принять

if (listen (socket_fd, Number_connection) <0 )
{
    perror("listen");
    return 1;
}
fd_set set;
struct timeval timeout;
int rv;
FD_ZERO(&set); /* clear the set */
FD_SET(socket_fd, &set); /* add our file descriptor to the set */

timeout.tv_sec = 20;
timeout.tv_usec = 0;

rv = select(socket_fd + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
{
    perror("select"); /* an error accured */
    return 1;
}
else if(rv == 0)
{
    printf("timeout occurred (20 second) \n"); /* a timeout occured */
    return 1;
}
else
    client_socket_fd = accept (socket_fd,(struct sockaddr *) &client_name, &client_name_len);
0 голосов
/ 11 августа 2010

Я бы поместил слушателя в отдельный процесс (поток), чтобы не портить вещи. И запустить рабочий процесс на другом для обработки существующих сокетов. Нет необходимости в неблокирующем слушателе. И нет нити накладных работает 2 нити.

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

Если вы хотите прослушать несколько портов и не хотите удерживать один процесс на слушателя, я предлагаю вам установить сокет в O_NONBLOCK и сделать что-то вроде:

// loop through listeners here and poll'em for read, when read is successful call accept, get descriptor, pass it to worker and continue listen
    while(1){
        foreach( serverSocket in ServerSockets ){
             if( serverSocket.Poll( 10, SelectRead ) ){
                  clientSocket = serverSocket.Accept();
                  // pass to worker here and release
             }

        }
    }
...