读取事件从未触发,使用libevent

时间:2015-02-05 11:46:09

标签: epoll libevent

我只是使用libevent编写一个echo服务器,但似乎永远不会触发read事件。代码是:

#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)。 有人可以帮我找出为什么永远不会触发读取事件?

1 个答案:

答案 0 :(得分:0)

基本上你不应该将接受的套接字设置为EV_WRITE,直到你真正想要写入套接字。你告诉libevent&#34;让我知道什么时候我可以写这个socket#34;这几乎总是如此。所以ServerWrite是在紧密循环中调用的。实际上,只有在编写缓冲区时才需要EV_WRITE,但是不写入所有字节。然后,您需要保存缓冲区的未写入部分,并使用EV_WRITE发出信号,以便再次写入套接字。