当前位置: 首页 > 文档资料 > PHP 进阶教程 >

14. PHP socket 初探 - 含着泪也要磕完 libevent(三)

优质
小牛编辑
157浏览
2023-12-01

其实在上一篇 libevent 文章中如果你总结能力很好的话,可以观察出来我们尝试利用 libevent 做了至少两件事情:

  • 毫秒级别定时器
  • 信号监听工具

大家都是码 php 的,也喜欢把自己说的洋气点儿:我是写服务器的。所以,今天的第一个案例就是拿 libevent 来构建一个简单粗暴的 http 服务器:

$host = '0.0.0.0';
$port = 9999;
$listen_socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
socket_bind( $listen_socket, $host, $port );
socket_listen( $listen_socket );

echo PHP_EOL.PHP_EOL."Http Server ON : http://{$host}:{$port}".PHP_EOL;

// 将服务器设置为非阻塞,此处概念可能略拐弯,建议各位查阅一下手册
socket_set_nonblock( $listen_socket );
// 创建事件基础体,还记得航空母舰吗?
$event_base = new EventBase();
// 创建一个事件,还记得歼15舰载机吗?我们将“监听socket”添加到事件监听中,触发条件是read,也就是说,一旦“监听socket”上有客户端来连接,就会触发这里,我们在回调函数里来处理接受到新请求后的反应
$event = new Event( $event_base, $listen_socket, Event::READ | Event::PERSIST, function( $listen_socket ){
  // 为什么写成这样比较执拗的方式?因为,“监听socket”已经被设置成了非阻塞,这种情况下,accept是立即返回的,所以,必须通过判定accept的结果是否为true来执行后面的代码。一些实现里,包括workerman在内,可能是使用@符号来压制错误,个人不太建议这>样做
  if( ( $connect_socket = socket_accept( $listen_socket ) ) != false){
    echo "有新的客户端:".intval( $connect_socket ).PHP_EOL;
    $msg = "HTTP/1.0 200 OK\r\nContent-Length: 2\r\n\r\nHi";
    socket_write( $connect_socket, $msg, strlen( $msg ) );
    socket_close( $connect_socket );
  }
}, $listen_socket );
$event->add();
$event_base->loop();

将代码保存为 test.php,然后 php http.php 运行起来。再开一个终端,使用 curl 的 GET 方式去请求服务器,效果如下:

这是一个非常非常简单地不能再简单的 http demo 了,对于一个完整的 http 服务器而言,他还差比较完整的 http 协议的实现、多核 CPU 的利用等等。这些,我们会放到后面继续深入的文章中开始细化丰富。

还记得我们使用 select 系统调用实现了一个粗暴的在线聊天室,select 这种业余的都敢出来混个聊天室,专业的绝对不能怂。