1. 程式人生 > >libevent實現C/S模型

libevent實現C/S模型

 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <event2/event.h>
 #include <event2/bufferevent.h>

 #define LISTEN_PORT 8000
 #define LIATEN_BACKLOG 32

/*********************************************************************************
*                   函式宣告
**********************************************************************************/
//accept回撥函式
void do_accept_cb(evutil_socket_t listener, short event, void *arg);
//read 回撥函式
void read_cb(struct bufferevent *bev, void *arg);
//error回撥函式
void error_cb(struct bufferevent *bev, short event, void *arg);
//write 回撥函式
void write_cb(struct bufferevent *bev, void *arg);
/*********************************************************************************
*                   函式體
**********************************************************************************/
//accept回撥函式
void do_accept_cb(evutil_socket_t listener, short event, void *arg)
{
  //傳入的event_base指標
  struct event_base *base = (struct event_base*)arg;
  
  struct sockaddr_in sin; //宣告地址
  socklen_t slen = sizeof(sin);  //地址長度宣告
  
  //接收客戶端,並返回新的套接字conn_fd用於通訊
  evutil_socket_t  conn_fd= accept(listener, (struct sockaddr *)&sin, &slen);
  if (conn_fd< 0)
  {
    perror("error accept");
    return;
  }
  printf("new client[%u]  connect success \n", conn_fd);
  
  //使用conn_fd建立bufferevent,並將bufferevent也安插到base上
  struct bufferevent *bev = bufferevent_socket_new(base, conn_fd, BEV_OPT_CLOSE_ON_FREE);
  bufferevent_setcb(bev, read_cb, NULL, error_cb, arg); //設定回撥函式read_cb \ error_cb
  bufferevent_enable(bev, EV_READ | EV_WRITE | EV_PERSIST);//啟用永久read/write
}
//read 回撥函式
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); //通過傳入引數bev找到socket fd
  
  while (n = bufferevent_read(bev, line, MAX_LINE))
  {
    line[n] = '\0';
    printf("fd=%u, read line: %s\n", fd, line);
   
    bufferevent_write(bev, line, n); //將獲取的資料回射給客戶端
  }
}
//error回撥函式
void error_cb(struct bufferevent *bev, short event, void *arg)
{
  //通過傳入引數bev找到socket fd
  evutil_socket_t fd = bufferevent_getfd(bev);
  //cout << "fd = " << fd << endl;
  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);
}
//write 回撥函式
void write_cb(struct bufferevent *bev, void *arg)
{
  char str[1024];
  evutil_socket_t fd = bufferevent_getfd(bev);//通過傳入引數bev找到socket fd
  printf("輸入資料:");
  scanf("%s",str);
  bufferevent_write(bev, &str, sizeof(str));
}
 
int main()
{
  evutil_socket_t listener;
  listener = socket(AF_INET, SOCK_STREAM, 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, 1000) < 0) {
    perror("listen");
    return 1;
  }
  
  printf("Listening...\n");
  
  evutil_make_socket_nonblocking(listener);
  
  struct event_base *base = event_base_new();
  //監聽套接字listener可讀事件:一旦有client連線,就會呼叫do_accept_cb回撥函式
  struct event *listen_event = event_new(base, listener, EV_READ | EV_PERSIST, do_accept_cb, (void*)base);

  event_add(listen_event, NULL);
  event_base_dispatch(base);

  return 0;
}