C / libev: программа закрывается при срабатывании события

У меня есть следующий код libev:

#include <ev.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <string.h>
#include <stdlib.h>
#include <sys/un.h>
#include <netinet/in.h>

ev_io stdin_watcher;

static void cb(EV_P_ ev_io *w, int revents){
        puts ("hello");

        //read file here - suggestion due to Ioan
        #define BUF_LEN 10
        char buf[BUF_LEN];
        memset(buf,0,BUF_LEN);
        int byte_read;
        while( (byte_read = recv(w->fd,buf,BUF_LEN-1,0)) > 0) {
                printf("len: %i: %s",byte_read,buf);
                memset(buf,0,BUF_LEN);
        }


        if(-1 == byte_read && EAGAIN != errno) {
            perror("recv");
        }
        close(w->fd);

        //ev_io_stop (EV_A_ w);
        //ev_unloop (EV_A_ EVUNLOOP_ALL);
}


int main (void){
        struct ev_loop *loop = ev_default_loop (0);
        int len;

        int sd;
        sd=socket(AF_UNIX,SOCK_STREAM,0);

        struct sockaddr_un address;
        //memset(&address,0,sizeof(address));
        address.sun_family=AF_UNIX;
        strcpy(address.sun_path,"/tmp/mysocket");
        unlink(address.sun_path);
        len=strlen(address.sun_path)+sizeof(address.sun_family);

        int x=bind(sd,(struct sockaddr*)&address,sizeof(address));
        printf("%d\n",x);
        listen(sd,5);

        ev_io_init(&stdin_watcher,cb,sd,EV_READ);
        ev_io_start(loop,&stdin_watcher);

        ev_loop (loop, 0);

        // unloop was called, so exit
        return 0;
}

Все работает нормально (почти). Скомпилируйте: gcc file.c -lev и запустите ./a.out. Затем напишите в сокет, который прослушивает ./a.out: echo "gobblydeegook" | nc -U /tmp/mysocket.

Привет, как и ожидалось, появится на консоли.

Но программа вызывает событие, а затем продолжает печатать «привет» до бесконечности! Я хочу, чтобы он продолжал отслеживать записи в этом сокете unix. Как это сделать?


person Eamorr    schedule 27.01.2012    source источник


Ответы (1)


Событие вызывается, когда в сокете есть данные для чтения. Поскольку вы не удаляете данные из сокета, а просто печатаете «hello», событие вызывается снова, чтобы вы могли обработать данные.

person Ioan    schedule 27.01.2012
comment
М-м-м. Это очень интересно, спасибо. Я попытался прочитать данные (см. Обновленный пост, но продолжаю получать сообщение об ошибке recv: Invalid argument. - person Eamorr; 27.01.2012
comment
libev также вызывает то же событие для ошибок в сокете, например, когда он закрыт. Поскольку вы закрываете сокет, событие вызывается снова, после чего вы пытаетесь получить доступ к закрытому сокету. - person Ioan; 27.01.2012
comment
да ладно ... Думаю, я тебя понимаю. Вы знаете, как этому противодействовать? - person Eamorr; 27.01.2012
comment
Проверьте документы на наличие recv и обработайте случай закрытого сокета. А еще лучше остановить наблюдателя, если вы закроете розетку. - person Ioan; 27.01.2012
comment
Также проверьте документацию на события libev IO. После закрытия сокета дескриптор становится недействительным и может привести к ошибкам, если тот же самый дескриптор будет повторно использован по незнанию. - person Ioan; 27.01.2012