高性能I/O框架库Libevent

Linux服务器程序处理的三类事件

I/O事件、信号事件和定时事件。

I/O框架库以库函数的形式,封装了较为底层的系统调用。

I/O框架库的组件

基于Reactor模式的I/O框架库包含的组件:句柄、事件多路分发器、事件处理器和具体的事件处理器。

  1. 句柄
    I/O框架库要处理的对象,即I/O事件、信号事件和定时事件,统一称为事件源。
    I/O事件对应的句柄是文件描述符,信号事件对应的句柄是信号值。

  2. 事件多路分发器
    即事件循环。内部调用的是select、poll、epoll_wait.

  3. 事件处理器和具体事件处理器

在这里插入图片描述

  1. 定义实例;
  2. 创建事件;
  3. 注册(添加)到libevent;
  4. 事件循环;

Libevent支持的事件类型:

在这里插入图片描述

代码实现

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5 #include<assert.h>
  6 #include<event.h>
  7 #include<signal.h>
  8 
  9 void sig_cb(int fd,short ev,void*arg)//回调函数
 10 {
 11     printf("sig=%d\n",fd);
 12 }
 13 void time_cb(int fd,short ev,void*arg)
 14 {
 15     printf("time out\n");
 16 }
 17 int main()
 18 {
 19     struct event_base*base=event_init();//定义一个实例(libevent) 框架
 20     assert(base!=NULL);
 21 
 22    struct event*sig_ev=evsignal_new(base,SIGINT,sig_cb,NULL); //定义信号事>    件
 23    assert(sig_ev!=NULL);
 24 
 25    event_add(sig_ev,NULL);//添加(注册)事件到libevent实例
 26 
 27    struct timeval tv={5,0};
 28    struct event*time_ev=evtimer_new(base,time_cb,NULL);//定义定时事件
 29    assert(time_ev!=NULL);
 30    event_add(time_ev,&tv);//设置(添加)超时事件
 31 
 32   event_base_dispatch(base); //启动事件循环
 33 
 34   event_free(sig_ev);
 35   event_free(time_ev);
 36   event_base_free(base);
 37 
 38   exit(0);
 39 }                    

编译时,注意连接库,加上 -levent

在这里插入图片描述
在这里插入图片描述

通过Libevent 检测多个客户端连接
自动调用I/O函数处理并发事件

客户端

#include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5 #include<assert.h>
  6 #include<sys/socket.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 
 10 int main()
 11 {
 12     int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字
 13     assert(sockfd!=-1);
 14 
 15     //bind()//可以绑定,但是一般不绑定
 16 
 17     struct sockaddr_in saddr;
 18     memset(&saddr,0,sizeof(saddr));
 19     saddr.sin_family=AF_INET;
 20     saddr.sin_port=htons(6000);
 21     saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
 22 
 23     int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//三次握手
 24     assert(res!=-1);
 25     while(1)
 26     {
 27         char buff[128]={0};
 28         printf("input:\n");
 29         fgets(buff,128,stdin);
 30 
 31         if(strncmp(buff,"end",3)==0)
 32         {
 33             break;
 34         }
 35         send(sockfd,buff,strlen(buff),0);
 36 
 37         memset(buff,0,128);
 38         recv(sockfd,buff,127,0);
 39         printf("buff=%s\n",buff);
 40     }
 41     close(sockfd);
 42 }

服务器

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5 #include<assert.h>
  6 #include<sys/socket.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 #include<event.h>
 10 
 11 void recv_cb(int fd,short ev,void*arg)
 12 {
 13     if(ev&EV_READ)
 14     {
 15         char buff[128]={0};
 16         int n=recv(fd,buff,127,0);
 17         if(n<=0)
 18         {
 19             struct event**p_cev=(struct event**)arg;
 20             event_free(*p_cev);
 21             free(p_cev);
 23             close(fd);
 22             printf("cilent close\n");
 23             return ;
 24         }
 25         printf("recv:%s\n",buff);
 26 
 27         send(fd,"ok",2,0);//写事件就绪,不用注册写事件,直接send
 28     }
 29 }
 30 void accept_cb(int fd,short ev,void* arg)
 31 {
 32     struct event_base* base=(struct event_base*)arg;
 33     if(base==NULL)
 34     {
 35         return ;
 36     }
 37     if(ev&EV_READ)
 38     {
 39         struct sockaddr_in caddr;
 40         int len=sizeof(caddr);
 41         int c=accept(fd,(struct sockaddr*)&caddr,&len);//接受连接
 42         if(c<0)
 43         {
 44             return ;
 45         }
 46         printf("accept c=%d\n",c);
 47         struct event**p_cev=(struct event**)malloc(sizeof(struct event*));
 48         if(p_cev==NULL)
 49         {
 50             return ;
 51         }
 52         *p_cev=event_new(base,c,EV_READ|EV_PERSIST,recv_cb,p_cev);//将c添加到libevent实例中
 53         //  struct event*c_ev=event_new(base,c,EV_READ|EV_PERSIST,recv_cb,base);
 54 
 55         if(*p_cev==NULL)
 56         {
 57             return ;
 58         }
 59         event_add(*p_cev,NULL);
 60     }
 61 
 62 }
 63 
 64 int socket_init();
 65 int main()
 66 {
 67     struct event_base*base=event_init();
 68     assert(base!=NULL);
 69 
 70     int sockfd=socket_init();
 71     assert(sockfd!=-1);
 72 
 73     struct event*sock_ev=event_new(base,sockfd,EV_READ|EV_PERSIST,accept_cb,base);
 74     event_add(sock_ev,NULL);
 75 
 76     event_base_dispatch(base);//启动事件循环
 77     event_free(sock_ev);
 78     event_base_free(base);
 79 }
 80 
 81 int socket_init()
 82 {
 83     int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字
 84     if(sockfd==-1)
 85     {
 86         return -1;
 87     }
 88 
 89     struct sockaddr_in saddr;
 90     memset(&saddr,0,sizeof(saddr));
 91     saddr.sin_family=AF_INET;
 92     saddr.sin_port=htons(6000);
 93     saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
 94     int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//指定监听>    套接子使用的是本主机的端口
 95     if(res==-1)
 96     {
 97         return -1;
 98     }
 99 
100     res=listen(sockfd,5);
101     if(res==-1)
102     {
103         return -1;
104     }
105     return sockfd;
106 
107 }

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值