libevent入门教程:Echo Server based on libevent

ent_set_timeouts(bev, struct timeval *READ, struct timeval *WRITE)来设置读写超时, 在error_cb里面处理超时。
    *. read_cb和write_cb的原型是
        void read_or_write_callback(struct bufferevent *bev, void *arg)
      error_cb的原型是
        void error_cb(struct bufferevent *bev, short error, void *arg) //这个是event的标准回调函数原型
      可以从bev中用libevent的API提取出event_base、sockfd、input/output等相关数据,详情RTFM~
    

    于是代码简化到只需要几行的read_cb和error_cb函数即可:

void  read_cb( struct  bufferevent *bev,   void  *arg) {
      char  line[256];
      int  n;
    evutil_socket_t fd = bufferevent_getfd(bev);
      while  (n = bufferevent_read(bev, line, 256), n > 0)
        bufferevent_write(bev, line, n);
}

void  error_cb( struct  bufferevent *bev,   short  event,   void  *arg) {
    bufferevent_free(bev);
}



    于是一个支持大并发量的echo server就成型了!下面附上无注释的echo server源码,110行,多抄几遍,就能完全弄懂啦!更复杂的例子参见官方文档里面的【Example: A simpler ROT13 server with Libevent】

# include  <stdio.h>
# include  <stdlib.h>
# include  <errno.h>
# include  <assert.h>

# include  <event2/event.h>
# include  <event2/bufferevent.h>

# define  LISTEN_PORT 9999
# define  LISTEN_BACKLOG 32

void  do_accept(evutil_socket_t listener,   short  event,   void  *arg);
void  read_cb( struct  bufferevent *bev,   void  *arg);
void  error_cb( struct  bufferevent *bev,   short  event,   void  *arg);
void  write_cb( struct  bufferevent *bev,   void  *arg);

int  main( int  argc,   char  *argv[])
{
      int  ret;
    evutil_socket_t listener;
    listener = socket(AF_INET, SOCK_STREAM, 0);
    assert(listener > 0);
    evutil_make_listen_socket_reuseable(listener);

      struct  sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(LISTEN_PORT);

      if  (bind(listener, ( struct  sockaddr *)&sin,   sizeof(sin)) < 0) {
        perror("bind");
          return  1;
    }

      if  (listen(listener, LISTEN_BACKLOG) < 0) {
        perror("listen");
          return  1;
    }

      printf  ("Listening...\n");

    evutil_make_socket_nonblocking(listener);

      struct  event_base *base = event_base_new();
    assert(base !=   NULL);
      struct  event *listen_event;
    listen_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, ( void*)base);
    event_add(listen_event,   NULL);
    event_base_dispatch(base);

      printf("The End.");
      return  0;
}

void  do_accept(evutil_socket_t listener,   short  event,   void  *arg)
{
      struct  event_base *base = ( struct  event_base *)arg;
    evutil_socket_t fd;
      struct  sockaddr_in sin;
    socklen_t slen;
    fd = accept(listener, ( struct  sockaddr *)&sin, &slen);
      if  (fd < 0) {
        perror("accept");
          return;
    }
      if  (fd > FD_SETSIZE) {
        perror("fd > FD_SETSIZE\n");
          return;
    }

      printf("ACCEPT: fd = %u\n", fd);

      struct  bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev, read_cb,   NULL, error_cb, arg);
    bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
}

void  read_cb( struct  bufferevent *bev,   void  *arg)
{
# define  MAX_LINE    256
      char  line[MAX_LINE+1];
      int  n;
    evutil_socket_t fd = bufferevent_getfd(bev);

      while  (n = bufferevent_read(bev, line, MAX_LINE), n > 0) {
        line[n] = '\0';
          printf("fd=%u, read line: %s\n", fd, line);

        bufferevent_write(bev, line, n);
    }
}

void  write_cb( struct  bufferevent *bev,   void  *arg) {}

void  error_cb( struct  bufferevent *bev,   short  event,   void  *arg)
{
    evutil_socket_t fd = bufferevent_getfd(bev);
      printf("fd = %u, ", fd);
      if  (event & BEV_EVENT_TIMEOUT) {
          printf("Timed out\n"); // if  bufferevent_set_timeouts() called
    }
      else   if  (event & BEV_EVENT_EOF) {
          printf("connection closed\n");
    }
      else   if  (event & BEV_EVENT_ERROR) {
          printf("some other error\n");
    }
    bufferevent_free(bev);
}

你可能感兴趣的:(socket,通信,epoll,libevent)