Linux---IO复用(libevent库)

Libevent

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。

Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomit、 Nylon、 Netchat等等,同时libevent是一个事件通知库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue、IOCP等系统调用管理事件机制。著名分布式缓存软件memcached也是基于libevent,而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。

我这里就先说说关于libevent的io方法
在这里插入图片描述

相关函数

1、event_init()

函数原型

struct event_base *event_init(void);

作用:创建libevent框架实例
所需头文件

#include <event.h>

返回值
成功:返回struct event_base*类型的框架
失败:NULL

2、event_new()

函数原型

struct event *event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)

所需头文件

#include <event.h>

返回值
成功:返回该fd所监听事件的结构体
失败:NULL

参数
base:即event_init()所创建好的框架
fd:描述符或信号
events:事件
cb :发现fd有某种事件时所调用的函数,由自己封装
arg:给自己所封装的函数传递的参数

注意:

void *cb(evutil_socket_t fd, short ev, void *arg)

在自己所封装的函数中
fd:描述符或信号
ev:所满足的事件
arg:传入的参数
当发生你所关注的事件的时候,便会调用你所封装的函数,封装的函数中前两个参数是由libevent的函数内部传入的,你只需要关注最后一个参数由event_new中最后一个参数传入即可

3、event_add()

函数原型

int event_add(struct event *ev, const struct timeval *tv)

所需头文件

#include <event>

参数
ev:为event_new的返回值
tv:超时时间

4、event_base_dispatch()

函数原型

int event_base_dispatch(struct event_base *event_base)

所需头文件

#include <event.h>

参数
event_base:所需要开始所关注事件的事件循环

5、event_free()

函数原型

void event_free(struct event *ev)

所需头文件

#include <event.h>

参数:
ev:需要关闭fd的事件结构体

6、event_base_free()

函数原型

void event_base_free(struct event_base *base)

所需头文件

#include <event.h>

参数:
base:需要被删除的框架,即event_init()的返回值

代码示例

例如:我们同过收到某种特定的信号来打印该信号所代表的数

#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <event.h>
#include <signal.h>

void sig_cb(int fd,short ev,void *arg)
{
    if(ev & EV_SIGNAL)
    {
        printf("\nsignal = %d\n",SIGINT);
    }
}

void time_cb(int fd,short ev,void *arg)
{
    if(ev & EV_TIMEOUT)
    {
        printf("time out\n");
    }
}

int main()
{
    struct event_base *base = event_init();
    assert(base!=NULL);

    struct event * sig_ev = event_new(base,SIGINT,EV_SIGNAL|EV_PERSIST,sig_cb,NULL);
    assert(sig_ev!=NULL);
    event_add(sig_ev,NULL);

    struct event *time_ev = event_new(base,-1,EV_TIMEOUT|EV_PERSIST,time_cb,NULL);
    assert(time_ev!=NULL);
    struct timeval time = {3,0};
    event_add(time_ev,&time);

    event_base_dispatch(base);

    event_free(sig_ev);
    event_free(time_ev);
    event_base_free(base);
    return 0;
}

运行结果为如下图
结果描述:当我在linux的终端上没有按下SIGINT信号(ctrl + c)时,程序不断打印time out 超时,当我发送该信号,则打印该信号所代表的数字
在这里插入图片描述

实现io多路

服务器

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <event.h>
#include <stdlib.h>

#define MAX 10

int Creat_Socket();

struct event *arr[1000];

void con_cb(int fd,short ev,void *arg)
{
    if(ev & EV_READ)
    {
        char buf[128] = {0};
        int size = recv(fd,buf,127,0);
        if(size<=0)
        {
            event_free(arr[fd]);
            arr[fd] = NULL;
            close(fd);
            printf("one client quit\n");
        }
        else
        {
            printf("client send message:\n%s",buf);
            send(fd,"success",7,0);
        }
    }

    if(ev & EV_TIMEOUT)
    {
        printf("time out\n");
    }
}

void accept_cb(int fd,short ev,void *arg)
{
    if(ev & EV_READ)
    {
        struct event_base *base = (struct event_base*)arg;

        struct sockaddr_in cliaddr;
        memset(&cliaddr,0,sizeof(cliaddr));
        socklen_t len = sizeof(cliaddr);

        int c = accept(fd,(struct sockaddr*)&cliaddr,&len);
        assert(c!=-1);
        printf("one client connect......fd = %d\n",c);

        struct event *con_ev = event_new(base,c,EV_READ|EV_PERSIST|EV_TIMEOUT,con_cb,NULL);
        assert(con_ev!=NULL);
        struct timeval time = {5,0};
        event_add(con_ev,&time);
        arr[c] = con_ev;
    }
}

int main()
{
    struct event_base *base = event_init();
    assert(base!=NULL);

    int sockfd = Creat_Socket();
    assert(sockfd!=-1);
    
    struct event *sock_ev = event_new(base,sockfd,EV_READ|EV_PERSIST|EV_TIMEOUT,accept_cb,(void*)base);
    assert(sock_ev!=NULL);
    event_add(sock_ev,NULL);
    arr[sockfd] = sock_ev;
    
    event_base_dispatch(base);

    event_free(sock_ev);
    event_base_free(base);

    return 0;
}


int Creat_Socket()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    assert(sockfd!=-1);

    struct sockaddr_in seraddr;
    memset(&seraddr,0,sizeof(seraddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(5000);
    seraddr.sin_addr.s_addr = htonl(INADDR_ANY);

    int bind_ret = bind(sockfd,(struct sockaddr*)&seraddr,sizeof(seraddr));
    assert(bind_ret!=-1);

    int listen_ret = listen(sockfd,MAX);
    assert(listen_ret!=-1);

    return sockfd;
}

客户端

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>

int main()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd < 0)
    {
        printf("creat socket fail\n");
        return -1;
    }
    else
    {
        printf("creat socket success , sockfd = %d\n",sockfd);
    }

    struct sockaddr_in cliaddr;
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_port = htons(5000);
    cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    memset(cliaddr.sin_zero,0,8);

    int confd = connect(sockfd,(struct sockaddr *)&cliaddr,sizeof(struct sockaddr));
    if(confd < 0)
    {
        printf("connect fail\n");
        close(sockfd);
        return -2;
    }
    else
    {
        printf("----------connect success-----------\nconfd = %d\n",confd);
    }

    char buf[128];
    while(1)
    {
        memset(buf,0,128);
        printf("send message to server\n");
        fgets(buf,128,stdin);
        send(sockfd,buf,strlen(buf),0);
        if(strncmp(buf,"end",3) == 0)
        {
            break;
        }
    }

    close(sockfd);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值