Skip to content

老陈是一个普通的文艺二逼青年

For The Dream

Libevent(一)

Written by chen

一、什么是libevent

libevent是一个事件触发的网络库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue、IOCP等系统调用管理事件机制。著名分布式缓存软件memcached也是基于libevent,而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。——引用自百度百科

需要注意以下几点:

  1. libevent是一个事件触发的网络库
  2. 可以跨平台(windows、linux、bsd等)
  3. 使用select、epoll(linux)、kqueue(freebsd)、IOCP(windows)等系统调用管理事件机制(IO复用)
  4. libevent在Linux环境下默认采用epoll作为IO多路复用方法

用户线程使用libevent则通常按以下步骤:

  1. 用户线程通过event_init()函数创建一个event_base对象。event_base对象管理所有注册到自己内部的IO事件。多线程环境下,event_base对象不能被多个线程共享,即一个event_base对象只能对应一个线程。
  2. 然后该线程通过event_add函数,将与自己感兴趣的文件描述符相关的IO事件,注册到event_base对象,同时指定事件发生时所要调用的事件处理函数(event handler)。服务器程序通常监听套接字(socket)的可读事件。比如,服务器线程注册套接字sock1的EV_READ事件,并指定event_handler1()为该事件的回调函数。libevent将IO事件封装成struct event类型对象,事件类型用EV_READ/EV_WRITE等常量标志。
  3. 注册完事件之后,线程调用event_base_loop进入循环监听(monitor)状态。该循环内部会调用epoll等IO复用函数进入阻塞状态,直到描述符上发生自己感兴趣的事件。此时,线程会调用事先指定的回调函数处理该事件。例如,当套接字sock1发生可读事件,即sock1的内核buff中已有可读数据时,被阻塞的线程立即返回(wake up)并调用event_handler1()函数来处理该次事件。
  4. 处理完这次监听获得的事件后,线程再次进入阻塞状态并监听,直到下次事件发生。

—— 引用自Memcached网络模型

二、php使用libevent扩展实现高性能服务器

此处不再赘述php-libevent扩展的安装。
上述在描述libevent步骤时候,用的并非php函数,php实现是略微有区别,大致流程不变。

在之前的文章『php-socket 实现简单服务器』中,我们使用stream+select的方式来实现一个简单的服务器。

现在我们就使用libevnet来实现更高性能的服务器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
# 创建服务端
$socket = stream_socket_server ('tcp://0.0.0.0:8888', $errno, $errstr);
# 设置 不阻塞
stream_set_blocking($socket, 0);
 
# 根据之前的libevent步骤的描述
# 1、创建event_base对象
$base = event_base_new();
# 2、创建感兴趣的文件描述符相关的IO事件
$event = event_new();
# 设置自己感兴趣的事件类型,以及回调方法
event_set($event, $socket, EV_READ | EV_PERSIST, 'callback', $base);
event_base_set($event, $base);
# 3、将时间注册到event_base对象去
event_add($event);
# 4、注册完事件之后,线程调用event_base_loop进入循环监听状态
event_base_loop($base);
 
function callback($socket, $flag, $base) {
    # 回调方法中主要做接收数据,并返回数据。
    $connection = stream_socket_accept($socket); //和客户端建立连接
    stream_set_blocking($connection, 0);
 
    fwrite($connection,  "HTTP/1.1 200 OK\r\n"
             . "Connection: close\r\n"
             . "Content-Type: text/html; charset=utf-8\r\n"
             . "\r\n"
             . "Hello World! " . date('Y-m-d H:i:s')
             ."\r\n\r\n"
     );
 
    fclose($connection);
}
 
 
?>
 
 

附上libevent的常量

1
2
3
4
5
6
7
8
9
10
值               常量名             含义
1               EV_TIMEOUT          超过时间后事件成为激活状态
2               EV_READ             FD就绪,可以读取的时候 ,事件成为激活状态
4               EV_WRITE            FD就绪,可以写入的时候 ,事件成为激活状态
8               EV_SIGNAL           用于实现信号检测
16              EV_PERSIST          表示事件是持久的
32              EV_ET               表示底层是否支持边沿触发事件
1               EVLOOP_ONCE         如果设置了EVLOOP_ONCE,循环将等待某些事件成为激活的,执行激活的事件直到没有更多的事件可以执行,然会返回。
2               EVLOOP_NONBLOCK     如果设置了EVLOOP_NONBLOCK,循环不会等待事件被触发:循环将仅仅检测是否有事件已经就绪,可以立即触发,如果有,则执
 

网络编程 · epoll, libevent, php, socket, stream, 服务器

Copyright © 2022 老陈是一个普通的文艺二逼青年. 沪ICP备13044041号-1