内容简介:原文地址:这段时间相比大家也看到了,本人离职了,一是在家偷懒实在懒得动手,二是好不容易想写点儿时间全部砸到数据结构和算法那里了。今儿回过头来,继续这里的文章。那句话是怎么说的:
原文地址: https://t.ti-node.com/thread/...
这段时间相比大家也看到了,本人离职了,一是在家偷懒实在懒得动手,二是好不容易想写点儿时间全部砸到数据结构和算法那里了。
今儿回过头来,继续这里的文章。那句话是怎么说的:
“ 自己选择的课题,含着泪也得磕完! ”(图文无关, 详情点击这里 )。
其实在上一篇libevent文章中( 《PHP socket初探 --- 硬着头皮继续libevent(二)》 ),如果你总结能力很好的话,可以观察出来我们尝试利用libevent做了至少两件事情:
- 毫秒级别定时器
- 信号监听工具
大家都是码 php 的,也喜欢把自己说的洋气点儿:“ 我是写服务器的 ”。所以,今天的第一个案例就是拿libevent来构建一个简单粗暴的http服务器:
<?php $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这种业余的都敢出来混个聊天室,专业的绝对不能怂。
无数个专业???????????????送给libevent!
啦啦啦啦,开始码:
<?php $host = '0.0.0.0'; $port = 9999; $fd = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); socket_bind( $fd, $host, $port ); socket_listen( $fd ); // 注意,将“监听socket”设置为非阻塞模式 socket_set_nonblock( $fd ); // 这里值得注意,我们声明两个数组用来保存 事件 和 连接socket $event_arr = []; $conn_arr = []; echo PHP_EOL.PHP_EOL."欢迎来到ti-chat聊天室!发言注意遵守当地法律法规!".PHP_EOL; echo " tcp://{$host}:{$port}".PHP_EOL; $event_base = new EventBase(); $event = new Event( $event_base, $fd, Event::READ | Event::PERSIST, function( $fd ){ // 使用全局的event_arr 和 conn_arr global $event_arr,$conn_arr,$event_base; // 非阻塞模式下,注意accpet的写法会稍微特殊一些。如果不想这么写,请往前面添加@符号,不过不建议这种写法 if( ( $conn = socket_accept( $fd ) ) != false ){ echo date('Y-m-d H:i:s').':欢迎'.intval( $conn ).'来到聊天室'.PHP_EOL; // 将连接socket也设置为非阻塞模式 socket_set_nonblock( $conn ); // 此处值得注意,我们需要将连接socket保存到数组中去 $conn_arr[ intval( $conn ) ] = $conn; $event = new Event( $event_base, $conn, Event::READ | Event::PERSIST, function( $conn ) use( $event_arr ) { global $conn_arr; $buffer = socket_read( $conn, 65535 ); foreach( $conn_arr as $conn_key => $conn_item ){ if( $conn != $conn_item ){ $msg = intval( $conn ).'说 : '.$buffer; socket_write( $conn_item, $msg, strlen( $msg ) ); } } }, $conn ); $event->add(); // 此处值得注意,我们需要将事件本身存储到全局数组中,如果不保存,连接会话会丢失,也就是说服务端和客户端将无法保持持久会话 $event_arr[ intval( $conn ) ] = $event; } }, $fd ); $event->add(); $event_base->loop();
将代码保存为server.php,然后php server.php运行,再打开其他三个终端使用telnet连接上聊天室,运行效果如下所示:
尝试放一张动态图试试,看看行不行,自己制作的gif都特别大,不知道带宽够不够。
截止到这篇为止,死磕Libevent系列的大体核心三把斧就算是抡完了,弄完这些,你在遇到这些代码的时候,就应该不会像下面这个样子了:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Zero to One
Peter Thiel、Blake Masters / Crown Business / 2014-9-16 / USD 27.00
“This book delivers completely new and refreshing ideas on how to create value in the world.” - Mark Zuckerberg, CEO of Facebook “Peter Thiel has built multiple breakthrough companies, and ......一起来看看 《Zero to One》 这本书的介绍吧!