之前一直认为workerman源码理解起很复杂,这段时间花了3个下午研究,其实只要理解 php如何守护化进程、信号、多进程、libevent扩展使用,对于如何实现就比较轻松了。
相关代码都在github地址里,具体注释都有。
守护化进程:
http://www.cnblogs.com/loveyouyou616/p/7867132.html
http://www.cnblogs.com/loveyouyou616/p/8881531.html
https://github.com/zhaocong222/workerman-learn/tree/master/test/daemon
信号与多进程:
http://www.cnblogs.com/loveyouyou616/p/8854835.html
https://github.com/zhaocong222/workerman-learn/tree/master/test/signal%26%26fork
libevent扩展使用:
https://github.com/zhaocong222/workerman-learn/tree/master/test/libevnt
以下为workerman读取socket数据的最简原型
<?php $eventBase = new EventBase(); $arr = []; function add($fd,$func){ global $arr,$eventBase; $event = new Event($eventBase, $fd, Event::READ | Event::PERSIST, $func, $fd); if (!$event||!$event->add()) { return false; } //关键点1 $arr[posix_getpid()][] = $event; } function baseRead($socket){ $buffer = @fread($socket, 2); echo $buffer."\n"; } function acceptConnection($socket){ $new_socket = @stream_socket_accept($socket, 0); // Thundering herd. if (!$new_socket) { return; } stream_set_blocking($new_socket, 0); //关键点2 stream_set_read_buffer($new_socket, 0); add($new_socket,'baseRead'); } $socketmain = stream_socket_server('tcp://127.0.0.1:4455', $errno, $errmsg, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN); //非阻塞 stream_set_blocking($socketmain,0); add($socketmain,'acceptConnection'); $eventBase->loop();
重点,重点,重点
ps: 这里需要注意2点,我就是在这2点琢磨了好久。
1. event实例一定要存放在一个全局数组里面 (应该是出了函数作用域就销毁了)
2. 如果fwrite的数据要大于 fread 设置的大小,要加上 stream_set_read_buffer($new_socket, 0); 读取stream时需要设置为无缓冲区
通过telnet来设置:
服务端打印的数据如下:
通过上面的代码 结合 信号 以及多进程 最后就是workerman的核心部分。