Swoole入门篇(上)
入门篇的服务对象是那些没有看过官方文档、没有接触过Swoole
框架的同学。
通过入门篇的学习,你将会了解Swoole
的一些基本入门知识。由于本小册的项目仅仅使用到了Swoole
中的部分技术,所以入门篇也只会为这些技术做一个Demo示范,尽量以更少的文字介绍更多的知识,有兴趣的同学也可以学习完本小册后,通过官方文档进行更深入地学习。根据学习金字塔来说,实践才是更高效的学习方式,对于一些技术的实际用法就请大家在小册的正式篇章中进行实战学习了。
编译安装
下载源码后,进入swoole-src
文件夹,并依次运行以下命令:
- phpize
- ./configure
- make
- make install
其中运行configure
的时候可以会报出一个错误:configure: error: Cannot find php-config. Please use --with-php-config=PATH
。这是因为无法找到php-config
文件,解决方法就是在后面使用参数的形式添加文件路径。
- ./configure —with-php-config=/usr/local/php/bin/php-config
执行完毕后就会看到以下提示:
[root@localhost swoole-src]# make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20170718/
Installing header files: /usr/local/php/include/php/
[root@localhost swoole-src]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20170718/
opcache.a opcache.so redis.so swoole.so yaconf.so
可以看到,swoole.so
文件已经编译出来了,下一步就是要引用这个文件作为我们php
的扩展。
编辑php.ini
文件,在其中加入一句代码:
- extension=swoole
运行php -m
:
[root@localhost swoole-src]# php -m
[PHP Modules]
...
swoole
...
只要显示出swoole
就代表安装成功了。
HTTP服务器
Swoole HTTP Server :wiki.swoole.com/wiki/page/3…
Swoole
创建一个HTTP Server
非常简单,只需要新建一个swoole_http_server
对象,并监听request
事件就能够完成普通的HTTP
请求了,我们来实验一下。
新建一个http_server.php
文件,并在其中编写以下代码:
$http = new swoole_http_server('0.0.0.0', 9501);
$http->on('request', function ($request, $response) {
$response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
});
$http->start();
上面代码就是创建了一个HTTP
服务器,并监听了9501
端口,当有请求进来的时候就会输出Hello Swoole
。
在CentOS
环境下运行命令:
- php http_server.php
看到这个界面就代表运行成功。
但是一般的接口请求都是带有一些参数的,在swoole_http_server
这里要怎么获取请求参数呢?童鞋们注意到request
回调函数中带有一个$request
变量了吗?没错,所有关于请求的数据都在这里,我们打印一下这个变量。
$http->on('request', function ($request, $response) {
var_dump($request);
$response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
});
重启服务器后,在访问的URL中增加请求参数?action=test_action
。
object(Swoole\Http\Request)#6 (10) {
...
["get"]=>
array(1) {
["action"]=>
string(11) "test_action"
}
...
}
在$request
对象的get
属性中,保存我们传入的参数action
和值test_action
。
使用面向对象创建HTTP服务器
我们上面创建的HTTP
服务器是使用面向过程的形式来编写的,使用面向对象会更符合现代的Web
开发。
做题时间
- 使用面向对象来编写一个
HTTP
服务器。
http_server.php
:
class Server
{
private $server;
public function __construct()
{
$this->server = new swoole_http_server('0.0.0.0', 9501);
$this->server->on('request', [$this, 'onRequest']);
$this->server->start();
}
public function onRequest($request, $response)
{
$response->end("<h1>Hello Swoole. #" . rand(1000, 9999) . "</h1>");
}
}
new Server();
只需要把swoole_http_server
创建出来的对象作为Server
类的成员属性,那就封装完成了。
WebSocket服务器
Swoole WebSocket Server:wiki.swoole.com/wiki/page/3…
Swoole
中内置了WebSocket
服务器,可以通过简单的代码来监听某个端口的WebSocket
连接。
做题时间
参考官方文档,使用面向对象的方式创建一个
WebSocket
服务器。<?php class WebSocketServer {
const HOST = '0.0.0.0';
const PORT = 9501;
private $server;
public function __construct()
{
$this->server = new swoole_websocket_server(self::HOST, self::PORT);
$this->server->set(array(
'worker_num' => 4
));
$this->server->on('start', [$this, 'onStart']);
$this->server->on('workerStart', [$this, 'onWorkerStart']);
$this->server->on('open', [$this, 'onOpen']);
$this->server->on('message', [$this, 'onMessage']);
$this->server->on('close', [$this, 'onClose']);
$this->server->start();
}
public function onStart($server)
{
swoole_set_process_name('websocket-server');
echo sprintf(
"master start (listening on %s:%d)\n",
self::HOST,
self::PORT
);
}
public function onWorkerStart($server, $workerId)
{
echo "server: onWorkStart,worker_id:{$server->worker_id}\n";
}
public function onOpen($server, $request)
{
echo "server: handshake success with fd{$request->fd}\n";
}
public function onMessage($server, $request)
{
echo "receive from {$request->fd}:{$request->data},opcode:{$request->opcode},fin:{$request->finish}\n";
$server->push($request->fd, "this is server");
}
public function onClose($server, $fd)
{
echo "client {$fd} closed\n";
}
}
new WebSocketServer();
创建WebSocket Server
时调用了set()
方法,并且绑定了五个回调方法。当接收到客户端消息时,将会发送一条this is server消息。
Server配置
可以通过调用set()
方法,为我们创建的WebSocket Server
进行参数配置,如以上代码则表示开启了4个worker
。
有童鞋想问worker有什么用呢?简单来说worker就是用到接受请求并且进行逻辑运算的一个进程,详情可以查看文档:wiki.swoole.com/wiki/page/1…
回调函数
- onStart:启动后在**主进程(master)**的主线程回调此函数。如果想要修改服务器后台进程名,就需要在这个回调函数中进行处理。
- onWorkerStart:此事件在
Worker
进程/Task
进程启动时发生。这里创建的对象可以在进程生命周期内使用。当设置了n
个worker
的时候,这个函数将会被回调n
次。在默认的dispatch_mode
模式下,每一个新连接都会随机分配一个worker
进程,并且在此连接断开前每一次的message
将会发送到同一个worker
进程。如果我们想发送消息到客户端,就可以使用此回调函数的第一个参数$server
对象。 - onOpen:当
WebSocket
客户端与服务器建立连接并完成握手后会回调此函数。 - onMessage:当服务器收到来自客户端的数据帧时会回调此函数。第一个参数
$server
与onWorkerStart()
方法中的参数$server
是同一个对象。第二个参数$request
实际是一个swoole_websocket_frame
对象,里面包含了4个属性,其中比较重要的是fd
和data
。fd
表示当前发送消息的客户端socket id
,想要给客户端发送消息就必须要通过这个fd
。data
则保存了客户端发来的数据。 - onClose:客户端连接关闭后,在worker进程中回调此函数,参数中的
$fd
就是客户端的连接fd
。
下面我们来添加一个前端的WebSocket
客户端,测试一下Swoole WebSocket
服务器是否正常。
新建一个index.html
文件,在里面输入以下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var wsServer = 'ws://192.168.3.41:9501';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
websocket.send("this is client");
console.log("Connected to WebSocket server.");
};
websocket.onclose = function (evt) {
console.log("Disconnected");
};
websocket.onmessage = function (evt) {
console.log('Retrieved data from server: ' + evt.data);
};
websocket.onerror = function (evt, e) {
console.log('Error occured: ' + evt.data);
};
</script>
</body>
</html>
前端代码很简单,仅仅是连接了服务端,在连接成功后会回调到onopen()
方法,发送this is client字符串到服务端。
打开页面并在chrome
浏览器中打开network
标签。
客户端成功发送this is client,同时也成功接收到了服务端发来的this is server。
[root@localhost PHPDemo]# php websocket_server.php
master start (listening on 0.0.0.0:9501)
server: onWorkStart,worker_id:0
server: onWorkStart,worker_id:2
server: onWorkStart,worker_id:3
server: onWorkStart,worker_id:1
server: handshake success with fd1
receive from 1:this is client,opcode:1,fin:1
服务端中也成功输出了客户端发来的消息。
小结
本章我们学习了Swoole
扩展的安装,一个简单的HTTP Server
的创建,使用面向对象的代码来封装一个Server
,一个简单的WebSocket Server
和WebSocket Client
。相信童鞋们应该对WebSocket
编程有了一点点体会了,下一章我们将会介绍更多Swoole
的基础功能。