swoole 学习日记 One
Posted woshihaiyong168
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swoole 学习日记 One相关的知识,希望对你有一定的参考价值。
定义:
不扯犊子,swoole就是php的一个扩展(C编写的)
一般我们php 用于web端开发 对于http协议是非常清楚的,但是要想java那样 做一些socket 之类 的是实时的、在线的这种,如果我们使用http协议的话 只能使用ajax轮询,对于服务器来说得不偿失,这个时候就是swoole派上用场的时候,他可以实现php 做游戏、聊天室等之类的实时通讯的东西,大家也知道其实不只swoole可以让PHP实现这些功能,例如:workerman、meepops (PHP编写)都是非常不错的,相对于swoole来说这些对phper学习成本较高(就是有难度),但是swoole因为是纯c编写的比php编写的workerman、meepops来说速度功能方面要更加出色!!
1、环境安装(swoole扩展)
cd /usr/local/src wget https://github.com/swoole/swoole-src/archive/v1.9.17.tar.gz tar -zxvf v1.9.17.tar.gz cd swoole-src-1.9.17/ /usr/local/php/bin/phpize ./configure --with-php-config=/usr/local/php/bin/php-config make && make install vim /usr/local/php/etc/php.ini extension=swoole.so service php-fpm reload2、入门教程网址 点击打开链接
包含模块:
swoole_server
强大的TCP/UDP Server框架,多线程,EventLoop,事件驱动,异步,Worker进程组,Task异步任务,毫秒定时器,SSL/TLS隧道加密。
- swoole_http_server是swoole_server的子类,内置了Http的支持
- swoole_websocket_server是swoole_http_server的子类,内置了WebSocket的支持
swoole_client
TCP/UDP客户端,支持同步并发调用,也支持异步事件驱动。
swoole_event
EventLoop API,让用户可以直接操作底层的事件循环,将socket,stream,管道等Linux文件加入到事件循环中。
eventloop接口仅可用于socket类型的文件描述符,不能用于磁盘文件读写
swoole_async
异步IO接口,提供了 异步文件系统IO,异步DNS查询,异步mysql等API。包括2个重要的子模块:
- swoole_timer,异步毫秒定时器,可以实现间隔时间或一次性的定时任务
- file,文件系统操作的异步接口
swoole_process
进程管理模块,可以方便的创建子进程,进程间通信,进程管理。
swoole_buffer
强大的内存区管理工具,像C一样进行指针计算,又无需关心内存的申请和释放,而且不用担心内存越界,底层全部做好了。
swoole_table
基于共享内存和自旋锁实现的超高性能内存表。彻底解决线程,进程间数据共享,加锁同步等问题。
swoole_table的性能可以达到单线程每秒读写50W次
编程注意点:
进程隔离
进程隔离也是很多新手经常遇到的问题。修改了全局变量的值,为什么不生效,原因就是全局变量在不同的进程,内存空间是隔离的,所以无效。所以使用swoole开发Server程序需要了解进程隔离问题。
- 不同的进程中PHP变量不是共享,即使是全局变量,在A进程内修改了它的值,在B进程内是无效的
- 如果需要在不同的Worker进程内共享数据,可以用Redis、MySQL、文件、Swoole\\Table、APCu、shmget等工具实现
- 不同进程的文件句柄是隔离的,所以在A进程创建的Socket连接或打开的文件,在B进程内是无效,即使是将它的fd发送到B进程也是不可用的
onStart事件在Master进程的主线程中被调用。在此回调响应之前Swoole Server已进行了如下操作
- 已创建了manager进程
- 已创建了worker子进程
- 已监听所有TCP/UDP端口
- 已监听了定时器
接下来要执行
- 主Reactor开始接收事件,客户端可以connect到Server
从1.7.5+ Master进程内不再支持定时器,onMasterConnect/onMasterClose2个事件回调也彻底移除。Master进程内不再保留任何PHP的接口。
在onStart中创建的全局资源对象不能在worker进程中被使用,因为发生onStart调用时,worker进程已经创建好了。新创建的对象在主进程内,worker进程无法访问到此内存区域,因此全局对象创建的代码需要放置在swoole_server_start之前。
3.onWorkerStart
描述:Worker进程启动的回调
函数原型:
function onWorkerStart( swoole_server $serv,int $worker_id);
参数 | 描述 |
---|---|
$serv | swoole_server对象 |
$worker_id | Worker进程的id |
说明:此事件在worker进程/task_worker启动时发生。
发生PHP致命错误或者代码中主动调用exit时,Worker/Task进程会退出,管理进程会重新创建新的进程 onWorkerStart/onStart是并发执行的,没有先后顺序
通过$worker_id参数的值来,判断worker是普通worker还是task_worker。$worker_id>= $serv->setting['worker_num'] 时表示这个进程是task_worker。
如果想使用swoole_server_reload实现代码重载入,必须在workerStart中require你的业务文件,而不是在文件头部。在onWorkerStart调用之前已包含的文件,不会重新载入代码。
可以将公用的,不易变的php文件放置到onWorkerStart之前。这样虽然不能重载入代码,但所有worker是共享的,不需要额外的内存来保存这些数据。
onWorkerStart之后的代码每个worker都需要在内存中保存一份 $worker_id是一个从0-$worker_num之间的数字,表示这个worker进程的ID $worker_id和进程PID没有任何关系
4.onConnect
描述:新连接接入时的回调
函数原型:
function onConnect( swoole_server $serv,int $fd, int $from_id);
参数 | 描述 |
---|---|
$serv | swoole_server对象 |
$fd | 连接的描述符 |
$from_id | reactor的id,无用 |
说明:有新的连接进入时,在worker进程中回调。onConnect/onClose这2个回调发生在worker进程内,而不是主进程。如果需要在主进程处理连接/关闭事件,请注册onMasterConnect/onMasterClose回调。onMasterConnect/onMasterClose回调总是先于onConnect/onClose被执行
5.onClose
描述:连接关闭时的回调
函数原型:
function onClose( swoole_server $serv,int $fd, int $from_id);
参数 | 描述 |
---|---|
$serv | swoole_server对象 |
$fd | 连接的描述符 |
$from_id | reactor的id,无用 |
说明:TCP客户端连接关闭后,在worker进程中回调此函数。无论close由客户端发起还是服务器端主动调用swoole_server_close关闭连接,都会触发此事件。 因此只要连接关闭,就一定会回调此函数。
6.onTask
描述:task_worker进程处理任务的回调
函数原型:
function onTask(swoole_server $serv, int $task_id, int $from_id, string $data);
参数 | 描述 |
---|---|
$serv | swoole_server对象 |
$task_id | 任务ID |
$from_id | 来自于哪个worker进程 |
$data | 任务内容 |
说明:在task_worker进程内被调用。worker进程可以使用swoole_server_task函数向task_worker进程投递新的任务。可以直接将任务结果字符串通过return方式返回给worker进程。worker进程将在onFinish回调中收到结果。注:如果serv->set(array('task_worker_num' => 8)) task_id 并不是从1-8 而是递增的。
7.onFinish
描述:task_worker进程处理任务结束的回调
函数原型:
function onFinish(swoole_server $serv, int $task_id, string $data);
参数 | 描述 |
---|---|
$serv | swoole_server对象 |
$task_id | 任务ID |
$data | 任务结果 |
说明:在此函数中会收到任务处理的结果,通过task_id和worker_id来区分不同的任务。
8.onTimer
描述:定时器触发的回调
函数原型:
function onTimer(swoole_server $serv, int $interval);
参数 | 描述 |
---|---|
$serv | swoole_server对象 |
$interval | 定时的间隔 |
说明:定时器被触发时,该函数被调用。通过interval来区分不同时间间隔的定时器。
php 服务端 demo:
<?php
class Server
private $serv;
public function __construct()
$this->serv = new swoole_websocket_server("0.0.0.0", 2888);
$this->serv->set(array(
'worker_num' => 4,
'daemonize' => false,
'max_request' => 10000,
'dispatch_mode' => 2,
'debug_mode' => 1,
'task_worker_num' => 4
));
//启动开始
$this->serv->on('Start', array($this, 'onStart'));
//与onStart同级
$this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
//webSocket open 连接触发回调
$this->serv->on('open', array($this, 'onOpen'));
//webSocket send 发送触发回调
$this->serv->on('message', array($this, 'onMessage'));
//webSocket close 关闭触发回调
$this->serv->on('Close', array($this, 'onClose'));
//tcp连接 触发 在 webSocket open 之前回调
$this->serv->on('Connect', array($this, 'onConnect'));
//tcp 模式下(eg:telnet ) 发送信息才会触发 webSocket 模式下没有触发
$this->serv->on('Receive', array($this, 'onReceive'));
// task_worker进程处理任务的回调 处理比较耗时的任务
$this->serv->on('Task', array($this, 'onTask'));
// task_worker进程处理任务结束的回调
$this->serv->on('Finish', array($this, 'onFinish'));
// 服务开启
$this->serv->start();
public function onStart(swoole_websocket_server $serv)
// $this->serv->tick(1000, function()
// echo 1;
// );
echo "Start\\n";
public function onWorkerStart(swoole_websocket_server $serv,$worker_id)
//判断是worker进程还是 task_worker进程 echo 次数 是worker_num+task_worker_num
if($worker_id<$this->serv->setting['worker_num'])
echo 'worder'.$worker_id."\\n";
else
echo 'task_worker'.$worker_id."\\n";
// echo "workerStart$worker_id\\n";
public function onOpen(swoole_websocket_server $serv,$request)
echo "server: handshake success with fd$request->fd\\n";
public function onMessage(swoole_websocket_server $serv,$frame)
echo "receive from $frame->fd:$frame->data,opcode:$frame->opcode,fin:$frame->finish\\n";
$param = array(
'fd' => $frame->fd
);
$this->serv->task( json_encode( $param ) );
// $server->push($frame->fd, "this is server");
public function onConnect( $serv, $fd, $from_id )
echo "Client $fd connect\\n";
echo "$from_id\\n";
public function onReceive( swoole_websocket_server $serv, $fd, $from_id, $data )
echo "Get Message From Client $fd:$data\\n";
// send a task to task worker.
// $param = array(
// 'fd' => $fd
// );
// $serv->task( json_encode( $param ) );
echo "Continue Handle Worker\\n";
public function onClose($serv, $fd)
echo "Client $fd close connection\\n";
public function onTask($serv, $task_id, $from_id, $data)
echo "This Task $task_id from Worker $from_id\\n";
echo "Data: $data\\n";
for ($i = 0; $i < 10; $i++)
sleep(1);
echo "Taks $task_id Handle $i times...\\n";
$fd = json_decode($data, true)['fd'];
echo "Data in Task $task_id";
// $serv->send($fd, "Data in Task $task_id");
return "Task $task_id's result";
public function onFinish($serv,$task_id, $data)
echo "Task $task_id finish\\n";
echo "Result: $data\\n";
$server = new Server();
以上是关于swoole 学习日记 One的主要内容,如果未能解决你的问题,请参考以下文章