событие чтения никогда не запускается, используя libevent

Я просто пишу эхо-сервер, используя libevent, но кажется, что событие чтения никогда не запускается. Код:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include <event.h>
#include <event2/event.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static short ListenPort = 19999;
static long ListenAddr = INADDR_ANY;//任意地址,值就是0
static int   MaxConnections = 1024;

static int ServerSocket;
static struct event ServerEvent;

int SetNonblock(int fd)
{
    int flags;
    if ((flags = fcntl(fd, F_GETFL)) == -1) {
            return -1;
    }

    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
            return -1;
    }
    return 0;
}

void ServerRead(int fd, short ev, void *arg)
{
    //1)when telnet on 1999 and send a string,this never prints,help!
    printf("client readble\n");
    fflush(stdout);
            struct client *client = (struct client *)arg;
    u_char buf[8196];
    int len, wlen;

    len = read(fd, buf, sizeof(buf));
    if (len == 0) {
            printf("disconnected\n");
            close(fd);
            event_del(&ServerEvent);
            free(client);
            return;
    } else if (len < 0) {
            printf("socket fail %s\n", strerror(errno));
            close(fd);
            event_del(&ServerEvent);
            free(client);
            return;
    }

    wlen = write(fd, buf, len);//1)client str never echo back
    if (wlen < len) {
            printf("not all data write back to client\n");
    }
}

void ServerWrite(int fd, short ev, void *arg)
{
//2)to be simple,let writer do nothing
/*  if(!arg)
    {
            printf("ServerWrite err!arg null\n");
            return;
    }
    int len=strlen(arg);
    if(len <= 0)
    {
            printf("ServerWrite err!len:%d\n",len);
            return;
    }
            int wlen = write(fd, arg, len);
        if (wlen<len) {
                printf("not all data write back to client!wlen:%d len:%d \n",wlen,len);
        }
*/
    return;
}


void ServerAccept(int fd, short ev, void *arg)
{
    int cfd;
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);
    int yes = 1;

    cfd = accept(fd, (struct sockaddr *)&addr, &addrlen);
    if (cfd == -1) {
    //3)this prints ok
            printf("accept(): can not accept client connection");
            return;
    }
    if (SetNonblock(cfd) == -1) {
            close(cfd);
            return;
    }

    if (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
            printf("setsockopt(): TCP_NODELAY %s\n", strerror(errno));
            close(cfd);
            return;
    }

    event_set(&ServerEvent, cfd, EV_READ | EV_PERSIST, ServerRead, NULL);
    event_set(&ServerEvent, cfd, EV_WRITE| EV_PERSIST, ServerWrite,NULL);
    event_add(&ServerEvent, NULL);

    printf("Accepted connection from %s \n", (char *)inet_ntoa(addr.sin_addr));
}
int NewSocket(void)
{
    struct sockaddr_in sa;

    ServerSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (ServerSocket == -1) {
            printf("socket(): can not create server socket\n");
            return -1;
    }
    if (SetNonblock(ServerSocket) == -1) {
            return -1;
    }

    memset(&sa, 0, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_port = htons(ListenPort);
    sa.sin_addr.s_addr = htonl(ListenAddr);

    if (bind(ServerSocket, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
            close(ServerSocket);
            printf("bind(): can not bind server socket");
            return -1;
    }

    if (listen(ServerSocket, MaxConnections) == -1) {
            printf("listen(): can not listen server socket");
            close(ServerSocket);
            return -1;
    }
    event_set(&ServerEvent, ServerSocket, EV_READ | EV_PERSIST, ServerAccept, NULL);
    if (event_add(&ServerEvent, 0) == -1) {
            printf("event_add(): can not add accept event into libevent");
            close(ServerSocket);
            return -1;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int retval;
    event_init();
    retval = NewSocket();
    if (retval == -1) {
       exit(-1);
    }
    event_dispatch();
    return 0;
}

Сервер тестируется с помощью Telnet, но клиент ничего не получает.
Детали вопроса размещены в виде комментариев в приведенном выше коде в 1), 2), 3). Может ли кто-нибудь помочь мне выяснить, почему событие чтения никогда не запускается?


person aishuishou    schedule 05.02.2015    source источник


Ответы (1)


в основном вы не должны устанавливать принятый сокет как EV_WRITE, пока вы действительно не захотите писать в сокет. Вы говорите libevent «дайте мне знать, когда я смогу писать в этот сокет», что почти всегда происходит. Таким образом, ServerWrite вызывается в тесном цикле. На практике единственный раз, когда вам нужно EV_WRITE, это если вы записываете буфер, но не все байты записаны. Затем вам нужно сохранить незаписанную часть буфера и использовать EV_WRITE, чтобы сигнализировать, когда сокет может быть снова записан.

person Martin Redmond    schedule 05.02.2015
comment
спасибо, но я хочу знать, почему serverread никогда не вызывается? - person aishuishou; 06.02.2015
comment
вы можете говорить о том, когда писать эхо-коды, приведенные здесь: github.com/jasonish/libevent-examples/blob/master/echo-server/ - person aishuishou; 06.02.2015
comment
ServerRead не вызывается, потому что он однопоточный, а ServerWrite — бесконечный цикл. Если вы поместите printf прямо в начало ServerWrite, вы поймете, что я имею в виду. Если вы выполните поиск примера на github для ev_write, он покажет вам, как использовать буферы для записи. - person Martin Redmond; 06.02.2015