Мультиплексирование ввода/вывода в сокетах

Мультиплексирование ввода/вывода в сокетах

11.05.2011 10:27:42 Просмотров 29 Источник

Написал такой кусочек кода:

struct pollfd fds[1];
fds[0].fd = intf->fd;
fds[0].events = POLLIN|POLLOUT;
rc = poll(fds, 1, timeout);
// произошло событие
if(rc > 0){
    if(fds[0].revents&(POLLERR|POLLHUP)){
        rc = ErrorHandling;
    }
    else if(fds[0].revents&POLLIN){
        // прием данных
        if((intf->RXBufCSize == 0) || (intf->RXBufCSize < BufCap)){
            rc = Receiving;
        }
        else{
            rc = WaitingIO;
        }
    }
    else if(fds[0].revents&(POLLOUT)){
        // передача данных
        if(intf->TXBufCSize > 0){
            rc = Transmiting;
        }
        else{
            rc = WaitingIO;
        }
    }
}
else{
    // таймаут вышел
    if(rc == 0){
        rc = WaitingIO;
    }
    else{
        rc = ErrorHandling;
    }
}

При разрыве соединения не возникает события POLLHUP, узнать о нем я могу только с помощью 0 который возвращает функция recv(). А так хочется с помощью poll() узнавать о разрыве. В чем может быть проблема?

У вопроса есть решение - Посмотреть?

Ответы - Мультиплексирование ввода/вывода в сокетах / Мультиплексирование ввода/вывода в сокетах

avp

11.05.2011 12:01:59

Ни в чем. Так с сокетами и задумано.

psyhitus

12.05.2011 11:27:34

Работает на свежих ядрах Linux, в моем случае возможно узнать о разрыве только через recv()

https://ru.stackoverflow.com/questions/13407/%d0%9c%d1%83%d0%bb%d1%8c%d1%82%d0%b8%d0%bf%d0%bb%d0%b5%d0%ba%d1%81%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b2%d0%b2%d0%be%d0%b4%d0%b0-%d0%b2%d1%8b%d0%b2%d0%be%d0%b4%d0%b0-%d0%b2-%d1%81%d0%be%d0%ba%d0%b5%d1%82%d0%b0%d1%85/13681#comment13699_13681
Если откровенно, я всегда (лет 20) использовал select(). Оба по сути одно и то же, хотя в man возможности poll() много шире. В select() при разрыве соединения сокет отмечается в маске событий для чтения. Действительно, о разрыве соединения мы узнаем по 0 от recv().
https://ru.stackoverflow.com/questions/13407/%d0%9c%d1%83%d0%bb%d1%8c%d1%82%d0%b8%d0%bf%d0%bb%d0%b5%d0%ba%d1%81%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b2%d0%b2%d0%be%d0%b4%d0%b0-%d0%b2%d1%8b%d0%b2%d0%be%d0%b4%d0%b0-%d0%b2-%d1%81%d0%be%d0%ba%d0%b5%d1%82%d0%b0%d1%85/13681#comment13719_13681
Дело вкуса использовать select() или poll(). Мне лично не понравились макросы в select(), поэтому использую poll() :-)
Является ответом!
unsigned

26.05.2011 11:48:45

0 на recv - это событие EOF, означающее "Читать уже нечего". Но ничего не говорит о возможности записи.

HUP - это разрыв соединения, означающее "Писать уже без толку". Но ничего не говорит о возможности чтения (в системном буфере возможно есть что считать).

Если сторона A вызовет shutdown(s, SHUT_WR), то на стороне B должен случится EOF. Если сторона A вызовет close(s), то по идее у B должен случиться HUP. Но протокол tcp не позволяет определить - close там был вызван или shutdown.

HUP на стороне B можно получить в таких случаях:

  1. Заранее сделать на стороне B shutdown(s, SHUT_WR) и работать только на чтение. Когда сторона A закроет соединение, на B случится HUP, т.к. закрыты оба канала tcp-соединения.

  2. У unix-сокетов такой проблемы нет. Сторона B сразу узнает о close(s) стороны A (т.е. случается HUP).

  3. При ошибке на tcp-сокете, несовместимой с жизнью сокета. Случается ERR и HUP одновременно.

  4. При ошибке неблокирующего connect(s,...). Соединения не было вообще, но все равно случается HUP.

  5. ... наверняка еще есть случаи.

Cocuco4ka

23.12.2011 04:05:45

Очень просто. В приеме данных проверить: Если recv() вернул 0, то значит пришло EOF. Тут и нужно закрывать соединение с данным пользователем. POLLHUP в данном случае не пригодится.

skegg

23.12.2011 05:26:44

Внесу свои 5 копеек. Может, поможет.

В мане написано, что POLLHUP возникает при невозможности писать, а при невозможности читать из дескриптора возникает POLLRDHUP (с ядра 2.6.17).

Закрыть X