长亭百川云 - 文章详情

轻量级开源高性能事件驱动库 libevent

Tinywan

46

2024-08-08

介绍

libevent是一个用C语言编写的、轻量级的开源高性能事件通知库,由 Niels ProvosNick Mathewson 开发。它提供了一种机制来执行事件通知,允许程序在单个线程中高效地处理多个事件源,包括IO事件、定时事件和信号事件,使得开发者能够构建出响应迅速且易于扩展的网络应用程序。特别是在需要处理大量并发连接的场景中。它支持多种平台,包括Linux、Unix和Windows,并且提供了跨平台的事件处理机制。

Github: https://github.com/libevent/libevent

核心概念

  • 事件循环(Event Loop) 。事件循环是libevent的核心,它不断地等待和分发事件。开发者需要创建一个事件循环,并在其中注册感兴趣的事件和相应的回调函数。当这些事件发生时,libevent会调用相应的回调函数来处理事件。
  • 事件(Event) 。在libevent中,事件是一个抽象的概念,代表了任何可以触发回调函数的情形。事件可以是网络IO(如可读、可写)、定时器超时或信号到达等。
  • 事件基础结构(Event Base) 。事件基础结构是管理事件循环和相关资源的核心结构。它负责事件的注册、分发和清理。每个event_base结构都维护着自己的事件循环和事件队列。

特性

  • 跨平台 :Libevent 支持多种操作系统,包括 Windows、Linux、BSD 和 macOS,提供了统一的接口来处理不同平台下的事件通知机制。
  • 高性能 :Libevent 基于事件驱动(event-driven)模型,采用非阻塞 I/O,对事件进行异步处理,能够高效地处理大量并发连接。
  • 轻量级 :专注于网络,与一些其他网络库相比,Libevent 的代码相对精炼、易读,且专注于网络功能,避免了不必要的复杂性。
  • 支持多种I/O多路复用技术 :支持 select、poll、epoll、kqueue、dev/poll 等多种 I/O 多路复用技术,可以根据不同的操作系统和需求选择合适的机制。
  • 支持多种事件类型 :包括网络 I/O、定时器和信号等事件,用户可以注册这些事件并指定相应的回调函数来处理。

安装与编译

libevent 的安装和编译相对简单,可以通过源码编译或使用包管理器(如: apt-getyum 等)进行安装。对于源码编译,通常需要先下载 Libevent 的源码包,然后解压、配置、编译和安装。

查看是否已经安装

ls -al /usr/lib | grep libevent

下载 libevent-2.1.12-stable.tar.gz

wget https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz

解压 libevent

tar -zxvf libevent-2.1.12-stable.tar.gz

配置安装目录

./configure --prefix=/usr/local/libevent-2.1.12

编译安装

make && make install

如果在 libevent 安装目录 make 之后会生成一个 .libs/ , 里面如果没有 libevent\_openssl.so 说明系统没有安装 openssl 库。但是如果安装了,依然没有这个文件生成,可能需要制定 openssl 路径。

ln -s  /usr/local/ssl/include/openssl    /usr/include/openssl

查看是否安装成功

$ ls -al /usr/local/ | grep libevent
drwxr-xr-x  5 root root 4096 Mar 17  2024 libevent-2.1.12

安装测试

sample 目录下会有已经编译好的服务器应用程序。

cd libevent-2.1.12-stable/sample

可以拿 hello-world 程序用来测试。

ls
dns-example        hello-world    http-connect.c               https_client-openssl_hostname_validation.o  le-proxy.c                     signal-test.o
dns-example.c      hello-world.c  http-connect.o               http-server                                 le_proxy-le-proxy.o            time-test
dns-example.o      hello-world.o  https-client                 http-server.c                               openssl_hostname_validation.c  time-test.c
event-read-fifo    hostcheck.c    https-client.c               http-server.o                               openssl_hostname_validation.h  time-test.o
event-read-fifo.c  hostcheck.h    https_client-hostcheck.o     include.am                                  signal-test
event-read-fifo.o  http-connect   https_client-https-client.o  le-proxy                                    signal-test.c

hello-world

服务端

./hello-world 

# 客户端连接响应如下
flushed answer

客户端

netcat 172.30.237.24 9995

Hello, World!

如果客户端收到 Hello, World! 字符串,表示 libevent 在本机可以正常使用。

http-server

当使用 ./http-server 命令来启动一个 HTTP 服务器。对于 http-server ,你可以使用 -p--port 参数来指定端口号。最后一个参数为服务器根目录。

具体的命令格式:

./http-server -p 8886 /home/www/build/libevent-2.1.12-stable/sample/
  • 端口: 8886
  • 根目录: /home/www/build/libevent-2.1.12-stable/sample/

这两个命令都会启动 http-server ,并让它监听在 8686 端口上。你可以通过浏览器访问 http://localhost:8686 来查看服务器上的内容。

在根目录: /home/www/build/libevent-2.1.12-stable/sample/ 新建一个静态测试文件 tinywan.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tinywan(ShaoBo Wan)</title>
</head>
<body>
<h1>开源技术小栈</h1>
</body>
</html>

服务端

./http-server -p 8886 /home/www/build/libevent-2.1.12-stable/sample/
Listening on 0.0.0.0:8886

Got a GET request for </tinywan.html>
Got a GET request for </tinywan.html>

客户端

curl -i http://172.30.237.24:8886/tinywan.html
HTTP/1.1 200 OK
Content-Type: text/html
Date: Thu, 08 Aug 2024 02:12:53 GMT
Content-Length: 165

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tinywan(ShaoBo Wan)</title>
</head>
<body>
<h1>开源技术小栈</h1>
</body>
</html>

访问首页

HTTP/1.1 200 OK
Content-Type: text/html
Date: Thu, 08 Aug 2024 02:16:21 GMT
Content-Length: 2206

<!DOCTYPE html>
<html>
 <head>
  <meta charset='utf-8'>
  <title>/</title>
  <base href='/'>
 </head>
 <body>
  <h1>/</h1>
  <ul>
    <li><a href="time-test.o">time-test.o</a>
    <li><a href="hello-world">hello-world</a>
    <li><a href="http-connect.c">http-connect.c</a>
    <li><a href=".deps">.deps</a>
    <li><a href="openssl_hostname_validation.c">openssl_hostname_validation.c</a>
    <li><a href=".libs">.libs</a>
    <li><a href="http-connect">http-connect</a>
    <li><a href="hostcheck.c">hostcheck.c</a>
    <li><a href="dns-example.o">dns-example.o</a>
    <li><a href="signal-test.o">signal-test.o</a>
    <li><a href=".">.</a>
    <li><a href="http-server.c">http-server.c</a>
    <li><a href="time-test.c">time-test.c</a>
    <li><a href="signal-test">signal-test</a>
    <li><a href="http-connect.o">http-connect.o</a>
    <li><a href="https_client-hostcheck.o">https_client-hostcheck.o</a>
    <li><a href="signal-test.c">signal-test.c</a>
    <li><a href=".dirstamp">.dirstamp</a>
    <li><a href="openssl_hostname_validation.h">openssl_hostname_validation.h</a>
    <li><a href="..">..</a>
    <li><a href="https_client-openssl_hostname_validation.o">https_client-openssl_hostname_validation.o</a>
    <li><a href="event-read-fifo.c">event-read-fifo.c</a>
    <li><a href="http-server.o">http-server.o</a>
    <li><a href="le-proxy.c">le-proxy.c</a>
    <li><a href="http-server">http-server</a>
    <li><a href="event-read-fifo.o">event-read-fifo.o</a>
    <li><a href="include.am">include.am</a>
    <li><a href="https_client-https-client.o">https_client-https-client.o</a>
    <li><a href="le_proxy-le-proxy.o">le_proxy-le-proxy.o</a>
    <li><a href="hello-world.c">hello-world.c</a>
    <li><a href="tinywan.html">tinywan.html</a>
    <li><a href="le-proxy">le-proxy</a>
    <li><a href="hostcheck.h">hostcheck.h</a>
    <li><a href="time-test">time-test</a>
    <li><a href="https-client">https-client</a>
    <li><a href="dns-example.c">dns-example.c</a>
    <li><a href="dns-example">dns-example</a>
    <li><a href="https-client.c">https-client.c</a>
    <li><a href="event-read-fifo">event-read-fifo</a>
    <li><a href="hello-world.o">hello-world.o</a>
</ul></body></html>

time-test

~/build/libevent-2.1.12-stable/sample$ ./time-test
timeout_cb called at 1723083770: 2.002 seconds elapsed.
timeout_cb called at 1723083772: 2.002 seconds elapsed.
timeout_cb called at 1723083774: 2.002 seconds elapsed.
timeout_cb called at 1723083776: 2.002 seconds elapsed.
timeout_cb called at 1723083778: 2.002 seconds elapsed.
timeout_cb called at 1723083780: 2.002 seconds elapsed.
timeout_cb called at 1723083782: 2.002 seconds elapsed.
timeout_cb called at 1723083784: 2.002 seconds elapsed.
timeout_cb called at 1723083786: 2.002 seconds elapsed.
timeout_cb called at 1723083788: 2.002 seconds elapsed.
timeout_cb called at 1723083790: 2.001 seconds elapsed.
timeout_cb called at 1723083792: 2.002 seconds elapsed.
timeout_cb called at 1723083794: 2.002 seconds elapsed.

应用场景

  • Web服务器 :Libevent 的高性能和异步I/O特性使其成为构建高性能Web服务器的理想选择。许多Web服务器,如Nginx的部分模块,都使用了Libevent来处理高并发连接。
  • 聊天服务器 :在即时通讯系统中,Libevent能够处理大量用户的实时消息推送和聊天功能。它支持非阻塞的socket I/O,使得单个线程可以管理成千上万个并发连接,非常适合构建高性能的聊天服务器。
  • 游戏服务器 :游戏服务器需要处理大量游戏客户端的连接请求和消息收发。Libevent能够高效地处理这些并发连接,支持大量玩家同时在线,确保游戏的流畅运行。
  • 分布式系统 :在分布式系统中,Libevent可以作为节点间通信的基础库,处理心跳检测、数据同步等任务。它的跨平台特性和高效的事件处理机制使得它非常适合在分布式系统中使用。
  • 高性能网络客户端 :除了服务器应用外,Libevent还可以用于构建高性能的网络客户端程序。通过其提供的事件驱动模型和非阻塞I/O特性,客户端程序可以高效地处理网络请求和响应。
  • 缓存系统 :著名的分布式缓存系统Memcached就是基于Libevent实现的。Memcached需要处理大量的并发读写请求,Libevent的高性能和异步I/O特性使其成为实现这种高性能缓存系统的关键组件。
  • RPC(远程过程调用)系统 :RPC系统需要高效地在不同节点之间传输数据和调用远程过程。Libevent的异步I/O和事件驱动特性使得它非常适合用于构建高性能的RPC系统。
  • 其他网络应用 :除了上述应用场景外,Libevent还可以用于构建各种需要高效处理并发连接的网络应用,如DNS服务器、FTP服务器、流媒体服务器等。

小结

总的来说,Libevent以其高性能、轻量级、跨平台和丰富的API等特性,在网络编程中发挥着重要作用,特别是在需要处理大量并发连接的应用场景中。

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2