基于libevent的socket服务端开发【Linux】

1 libevent简介

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

​ Libevent是一个事件通知库,内部使用select、poll、kqueue、IOCP等系统调用管理事件机制。Libevent是用C语言编写的,而且几乎是无处不用函数指针。Libevent支持多线程编程。Libevent已经被广泛应用,作为不少知名软件的底层网络库,比如memcached、Vomit、Nylon、Netchat等。

2 libevent安装

  1. 下载libevent安装包,下载地址:http://libevent.org/
  2. 解压安装包,并进入到解压后的目录
tar -zxvf libevent-2.1.12-stable
cd libevent-2.1.12-stable/
  1. 检测安装环境
./configure
  1. 编译源文件,生成.o文件和可执行文件
make
  1. 安装
make install

3 libevent相关函数介绍

libevent的地基–event_base

struct event_base* event_base_new(void)

函数说明:获得event_base结构

参数:无

返回值

  • 成功返回event_base结构体指针
  • 失败返回NULL
void event_base_free(struct event_base*)	//event.h

函数说明:释放event_base指针

int event_reinit(struct event_base* base)	//event.h

函数说明:如果有子进程,且子进程也要使用base,则子进程需要对event_base重新初始化,此时需要调用event_reinit函数

函数参数:由event_base_new返回的执行event_base结构的指针

返回值:成功返回0,失败返回-1

等待事件产生–循环等待 event_loop

​ libevent在地基打好之后,需要等待事件的产生,也就是等待事件被激活,所以程序不能退出,对于epoll来说,我们需要自己控制循环,而在 libevent中也给我们提供了API接口,类似while(1)的功能。

函数如下:

int event_base_dispatch(struct event_base* base)

函数说明:进入循环等待事件

函数说明:由event_base_new函数返回的指向event_base结构的指针

使用libevent库的步骤:

  1. 创建根节点–event_base_new

  2. 设置监听事件和数据可读可写的事件的回调函数

    设置了事件对应的回调函数以后,当事件产生的时候会自动调用回调函数

  3. 事件循环–event_base_dispatch

    相当于while(1),在循环内部等待事件的发生,若有事件发生则会触发事件对应的回调函数。

  4. 释放根节点–event_base_free

    释放由event_base_new 和event_new创建的资源,分别调用event_base_free和event_free函数。

4 基于libevent实现tcp协议的简单socket服务端通信

#include<iostream>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<event2/event.h>
#include<unistd.h>
#include<map>

std::map<int, struct event*> collection;
void readcb(evutil_socket_t fd, short events, void* arg) {
	char buf[BUFSIZ];
	int n;
	while (true)
	{
		n = read(fd, buf, sizeof(buf));
		if (n <= 0) {
			close(fd);
			//将通信文件描述符对应的事件从base上删除
			event_del(collection[fd]);
			std::map<int, struct event*> ::iterator it = collection.find(fd);
			collection.erase(it);
			printf("client exit,the current number of connection is %d\n", collection.size());
			break;
		}
		for (int i = 0; i < n; i++) {
			buf[i] = toupper(buf[i]);
		}
		printf("recv:%s", buf);
		write(fd, buf, n);
		if (n < BUFSIZ) {
			break;
		}
	}
}
void conncb(evutil_socket_t fd, short events, void* arg) {
	struct event_base* base = (struct event_base*)arg;
	struct sockaddr_in client_addr;
	socklen_t len = sizeof(client_addr);
	//接收新的客户端连接
	int cfd = accept(fd, (struct sockaddr*)&client_addr, &len);
	printf("a new connection is estistabled,ip:%s port:%d\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
	if (cfd > 0) {
		struct event* connev = event_new(base, cfd, EV_READ | EV_PERSIST, readcb, NULL);
		if (connev == NULL) {
			//退出循环
			event_base_loopexit(base, NULL);
			exit(0);
		}
		collection[cfd] = connev;
		printf("the current number of connection is %d\n", collection.size());
		//将通信文件描述符对应的事件event_base
		event_add(connev, NULL);
	}
}

int main() {
	int lfd = socket(AF_INET, SOL_SOCKET, 0);

	if (lfd == -1) {
		perror("socket create fail!");
	}
	//设置端口复用
	int opt = 1;
	setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
	struct sockaddr_in serv;
	serv.sin_family = AF_INET;
	serv.sin_addr.s_addr = htonl(INADDR_ANY);
	serv.sin_port = htons(8888);
	bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
	listen(lfd, 1024);

	//创建地基
	struct event_base* base = event_base_new();
	if (base == NULL) {
		perror("event base create error!");
	}
	//创建监听文件描述符事件
	struct event* ev = event_new(base, lfd, EV_READ | EV_PERSIST, conncb, base);
	if (ev == NULL) {
		perror("event new error!\n");
		return -1;
	}
	//将新的事件节点上base地基
	event_add(ev, NULL);
	//进入事件循环等待
	event_base_dispatch(base);
	//释放资源
	event_base_free(base);
	event_free(ev);

	return 0;
}
  • 17
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dream1909

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值