URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 2892
[ Назад ]

Исходное сообщение
"Ф-ция POLL , 3 дня умственных терзаний+банка кофе в поисках ошибки"

Отправлено Povesa , 05-Май-04 02:09 
Подскажите пожалуйста, в чём же ошибка. Почему я не могу перехватить POLLHUP  POLLERR ??
Программа должна при обрыве или завершении связи вызвать return 0;


#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <resolv.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <netinet/in.h>

#define PORT 6666
#define TIME_OUT 300
struct pollfd fds[1];
int main(void)
{
struct sockaddr_in addr;
int value=1;int cl=1,result,k,addr_len=sizeof(addr),sd;
char buffer[256];
int bytes;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
setsockopt(sd,SOL_SOCKET,SO_REUSEADDR, &value,sizeof(value));
if ( bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == 0 )
{
                listen(sd,5);
fds[0].fd=accept(sd,0,0);
fcntl(fds[0].fd,F_SETFL,O_NONBLOCK);
fds[0].events=POLLIN|POLLHUP;
for (;;)
{
if ( (result = poll(fds, 1, 500)) > 0 )
{
        if(((fds[0].revents&POLLHUP) == POLLHUP) ||
           ((fds[0].revents&POLLERR) == POLLERR) ||
           ((fds[0].revents&POLLNVAL) == POLLNVAL))
          {puts("POLLHUP");return 0;}
if ( (fds[0].revents & POLLIN)==POLLIN )
{
recv(fds[0].fd,buffer,sizeof(buffer),0);
puts(buffer);
printf("POLLIN\n");
}
}
else if ( result < 0 )
{perror("poll() error");exit(0);}
}
}
return 0;
}


Содержание

Сообщения в этом обсуждении
"Ф-ция POLL , 3 дня умственных терзаний+банка кофе в поисках ..."
Отправлено Alexander S. Salieff , 07-Май-04 15:43 
>Подскажите пожалуйста, в чём же ошибка. Почему я не могу перехватить POLLHUP
> POLLERR ??
>Программа должна при обрыве или завершении связи вызвать return 0;
>
>
>#include <stdio.h>
>#include <unistd.h>
>#include <sys/socket.h>
>#include <resolv.h>
>#include <sys/poll.h>
>#include <fcntl.h>
>#include <netinet/in.h>
>
>#define PORT 6666
>#define TIME_OUT 300
>struct pollfd fds[1];
>int main(void)
>{
>struct sockaddr_in addr;
>int value=1;int cl=1,result,k,addr_len=sizeof(addr),sd;
>char buffer[256];
>int bytes;
>sd = socket(PF_INET, SOCK_STREAM, 0);
>bzero(&addr, sizeof(addr));
Тут советую юзать memset (но это так, просто не по теме)

>addr.sin_family = AF_INET;
>addr.sin_port = htons(PORT);
>addr.sin_addr.s_addr = INADDR_ANY;
>setsockopt(sd,SOL_SOCKET,SO_REUSEADDR, &value,sizeof(value));
>if ( bind(sd, (struct sockaddr *)&addr, sizeof(addr)) == 0 )
>{
>            
>    listen(sd,5);
>fds[0].fd=accept(sd,0,0);
>fcntl(fds[0].fd,F_SETFL,O_NONBLOCK);
А это-то зачем? У тебя же есть мультиплексор в лице POLL. Не надо играцца с разблокированными сокетами, тока гемору огребешь, да и POLL в классическом варианте юзают на блокированном сокете

>fds[0].events=POLLIN|POLLHUP;
>for (;;)
>{
>if ( (result = poll(fds, 1, 500)) > 0 )
>{
>        if(((fds[0].revents&POLLHUP) == POLLHUP) ||
>
>           ((fds[0].revents&POLLERR)
>== POLLERR) ||
>           ((fds[0].revents&POLLNVAL)
>== POLLNVAL))
Тут не совсем верно. Р-евенты заполняются тоже мультиплексорно, т.е. вполне реальна ситуация, что у тебя будет промаскирована и POLLIN и POLLHUP одновременно (тогда условие (fds[0].revents&POLLHUP) == POLLHUP не проканает). Т.е. лучше делать просто if (fds[0].revents&POLLERR || fds[0].revents&POLLHUP || fds[0].revents&POLLNVAL) {}

>          {puts("POLLHUP");return 0;}
>
>if ( (fds[0].revents & POLLIN)==POLLIN )
>{
>recv(fds[0].fd,buffer,sizeof(buffer),0);
Ну и судя по оформлению вот этого ресива, он ошибки раньше словит, чем poll-мультиплексор. При нормальном разрыве соединения он вернет 0 (странно что ты возврат не проверяешь) а потом только придет р-евент POLLHUP, а при аварийном у тебя прога ваще упадет с SIGPIPE (ибо в ресиве нету флага MSG_NOSIGNAL). Т.е. тут можно классический перехват сделать вроде
if (recv(fds[0].fd,buffer,sizeof(buffer),MSG_NOSIGNAL)<=0) {Типа наелись}

И еще, как раз изза мультимаскирования р-евентов лучше сначала проверять полезные флаги (POLLIN POLLOUT) а потом уже ошибочные. Ибо тебе может придти мультисет POLLIN+POLLHUP, к примеру, а ты по POLLHUP'у сразу все прибъешь и похоронишь хвостик данных.

>puts(buffer);
>printf("POLLIN\n");
>}
>}
>else if ( result < 0 )
>{perror("poll() error");exit(0);}
>}
>}
>return 0;
>}



"Ф-ция POLL , 3 дня умственных терзаний+банка кофе в поисках ..."
Отправлено Alexander S. Salieff , 07-Май-04 15:49 
>fds[0].events=POLLIN|POLLHUP;
В догонку - выдержка из мана:
...или событий типа POLLERR, POLLHUP или POLLNVAL (эти три битовых флага не имеют смысла при использовании в поле events и будут установлены в поле revents, если соответствующее условие истинно.)

Так что |POLLHUP - это излишество ;)


"Ф-ция POLL , 3 дня умственных терзаний+банка кофе в поисках ..."
Отправлено Maxim Y. Moroz , 12-Май-04 05:07 
По поводу игр с блокируемыми сокетами.
Как раз не рекомендуется играться с блокированными сокетами, потому как возможна ситуация, что все нафик заблокируется. При работе с сетью даже при демультиплексировании событий сокеты нужно делать неблокируемыми.

"Ф-ция POLL , 3 дня умственных терзаний+банка кофе в поисках ..."
Отправлено Alexander S. Salieff , 14-Май-04 19:25 
>По поводу игр с блокируемыми сокетами.
>Как раз не рекомендуется играться с блокированными сокетами, потому как возможна ситуация,
>что все нафик заблокируется. При работе с сетью даже при демультиплексировании
>событий сокеты нужно делать неблокируемыми.

Ну это уже из области извратов. Получать от ядра сигнал, что есть данные, но на всякий случай деблочить сокет (а вдруг их нету? ;)))... Если уж ядру не доверять, то нах ты выбрал данную ОС для реализации?