服务器端

  要实现网络通信,肯定会用到socket等函数,这几个函数应该没什么问题。libevent默认情况下是单线程的,可以配置成多线程,每个线程有一个event_base,对应一个struct event _base结构体以及一个事件管理器,调度托管给它的一系列事件。所以当一个事件发生后,先创建一个event_base,再创建一个事件,将这个事件绑定,然后添加到event_base中,启动event_base的循环,开始处理事件。大概流程如下:

  1 参数解析;

  2. 创建socket连接;

  3. struct event_base *base = event_base_new();创建一个event_base;

  event_base_new()函数分配并且返回一个新的具有默认设置的 event_base。函数会检测环境变量,返回一个到 event_base 的指针。如果发生错误,则返回 NULL。选择各种方法时,函数会选择 OS 支持的最快方法。

  4struct event* listen_event;创建一个监听事件;

  5event_new(base,listenfd,EV_READ | EV_PERSIST,accept_cb,base);使用event_new()函数将监听事件绑定;

  参数:event_base监听的对象,需要监听的事件,事件发生后的回调函数,传给回调函数的参数。libevent支持的事件及属性包括(使用bitfield实现)

  EV_TIMEOUT:超时;

  EV_READ:只要网络缓冲中还有数据,回调函数就会被触发;

  EV_WRITE:只要塞给网络缓冲的数据被写完,回调函数就会被触发;

  EV_SIGNAL:POSIX信号量;

  EV_PERSIST:不指定这个属性,回调函数被触发后事件会被删除;

  EV_ET:Edge-Trigger边缘触发

  6event_add(listen_event,NULL);将监听事件绑定到event_base中;

  7event_base_dispatch(base);启动循环开始处理事件;

  8事件发生时的回调函数typedef void(* event_callback_fn)(evutil_socket_t sockfd, short event_type, void *arg)

  传给callback_func的是一个监听的事件类型fd,以及event_new中最后一个参数。

  如下是代码:

  int main(int argc,char **argv)

  {

  int listenfd;

  int ch;

  int port;

  struct option opt[]={

  {"port",required_argument,NULL,'p'},

  {"help",no_argument,NULL,'h'},

  {NULL,0,NULL,0}

  };

  while( (ch=getopt_long(argc,argv,"p:h",opt,NULL))!=-1 )

  {

  switch(ch)

  {

  case 'p':

  port=atoi(optarg);

  break;

  case 'h':

  print_help(argv[0]);

  return 0;

  }

  }

  printf("port:%d\n",port);

  if( !port )

  {

  print_help(argv[0]);

  return 0;

  }

  listenfd=socket_init(NULL,port);

  if( listenfd<0 )

  {

  printf("socket_init failure!\n");

  return -1;

  }

  printf("socket_init successfully!\n");

  /*创建一个event_base*/

  struct event_base *base = event_base_new();

  assert(base != NULL);//设置event_base不为空

  /*创建并绑定一个event*/

  struct event* listen_event;

  listen_event=event_new(base,listenfd,EV_READ | EV_PERSIST,accept_cb,base);

  /*添加监听事件*/

  event_add(listen_event,NULL);

  /*启动循环,开始处理事件*/

  event_base_dispatch(base);

  return 0;

  }

  /*回调函数accept_cb*/

  void accept_cb(int fd, short events, void* arg)

  {

  struct sockaddr_in cliaddr;

  evutil_socket_t clifd;

  socklen_t len=sizeof(cliaddr);

  clifd=accept(fd,(struct sockaddr*)&cliaddr,&len);

  if( clifd<0 )

  {

  printf("accept client %d failure!\n",clifd);

  close(clifd);

  }

  evutil_make_socket_nonblocking(clifd);//设置为非阻塞模式

  printf("accept client %d successfully!\n",clifd);

  struct event_base* base = (struct event_base*)arg;

  /*动态创建一个event结构体,并将其作为回调参数传递给*/

  struct event* cli_event = event_new(NULL, -1, 0, NULL, NULL);

  event_assign(cli_event,base, clifd, EV_READ | EV_PERSIST,read_cb, (void*)cli_event);

  event_add(cli_event,NULL);

  }

  /*accept的回调函数read_cb*/

  void read_cb(int fd, short events, void* arg)

  {

  int rv;

  char buf[1024];

  struct event* ev = (struct event*)arg;

  rv=read(fd,buf,sizeof(buf));

  if( rv<=0 )

  {

  printf("read message failure!\n");

  event_free(ev);

  close(fd);

  return ;

  }

  printf("read message successfully:%s\n",buf);

  char reply_buf[1024] = "I have received the msg: ";

  strcat(reply_buf + strlen(reply_buf), buf);

  write(fd,reply_buf,sizeof(reply_buf));

  }

  客户端

  客户端的实现与服务器端基本相似,先实现socket的连接,然后创建event_base,创建并绑定监听事件,添加监听事件,启动循环,开始处理事件。代码如下:

  int main(int argc, char** argv)

  {

  int ch;

  int sockfd;

  char *server_ip=NULL;

  int server_port=0;

  struct option opt[]={

  {"server_ip",required_argument,NULL,'i'},

  {"server_port",required_argument,NULL,'p'},

  {"help",no_argument,NULL,'h'},

  {NULL,0,NULL,0}

  };

  while( (ch=getopt_long(argc,argv,"i:p:h",opt,NULL))!=-1 )

  {无锡妇科医院 http://www.xasgyy.net/

  switch(ch)

  {

  case 'i':

  server_ip=optarg;

  break;

  case 'p':

  server_port=atoi(optarg);

  break;

  case 'h':

  print_help(argv[0]);

  return 0;

  }

  }

  if(!server_port)

  {

  print_help(argv[0]);

  return 0;

  }

  sockfd=socket_connect(server_ip,server_port);

  if( sockfd<0 )

  {

  printf("connect to server failure!\n");

  return -1;

  }

  printf("connect to server successfully!\n");

  struct event_base* base = event_base_new();

  struct event *sockevent = event_new(base, sockfd, EV_READ | EV_PERSIST, read_cb, NULL);

  event_add(sockevent, NULL);

  //监听终端输入事件

  struct event* ev_input = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, input_cb, (void*)&sockfd);

  event_add(ev_input, NULL);

  event_base_dispatch(base);

  printf("finished \n");

  return 0;

  }

  /*读回调函数*/

  void read_cb(int fd, short events, void *arg)

  {

  char buf[1024];

  int rv;

  rv=read(fd,buf,sizeof(buf));

  if( rv<=0 )

  {

  printf("read data from server %dfailure!\n",fd);

  exit(1);

  }

  printf("read %d data from server:%s\n",rv,buf);

  }

  /*输入信息回调函数*/

  void input_cb(int fd, short events, void* arg)

  {

  char buf[1024];

  int rv;

  rv=read(fd,buf,sizeof(buf));

  if( rv<=0 )

  {

  printf("read failure!\n");

  exit(1);

  }

  //把终端的消息发送给服务器端

  int sockfd = *((int*)arg);

  write(sockfd,buf,rv);

  }