简介

适用于 客户端-服务端 客户端-客户端 一对多 多对多的关系,多个客户端之间的长连接通信,聊天室,在线客服,服务端反向推送播报消息

特性:多进程,长连接,高并发,常驻内存…

  • 客户端与worker进程
    客户端与worker进程.png
    客户端与worker进程.png
  • 主进程与worker子进程
    主进程与worker子进程.png
    主进程与worker子进程.png

使用Workerman可以做很多有趣的事。(工业自动化,互联网工业,PLC机械报警…),通过长连接取数据,操作数据等,但PHP并不适用于工业领域。做一个仿im聊天工具,除了前端展示界面,后端也要考虑全面,更多的依赖于长连接。

本文参考 workerman官方文档
本文参考 thinksocketio - 基于socketio的聊天室Demo

安装Workerman框架

服务端

创建一个文件夹 我这里使用 testWebSocket

1
2
mkdir testWebSocket
cd testWebSocket

  • git形式安装(推荐)
    1
    git clone https://github.com/walkor/Workerman

根据官方文档创建一个示例 在 testWebSocket 下创建一个 PHP文件 test.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';

// 注意:这里与上个例子不同,使用的是websocket协议
$ws_worker = new Worker("websocket://0.0.0.0:2000");

// 启动4个进程对外提供服务
$ws_worker->count = 4;

// 当收到客户端发来的数据后返回hello $data给客户端
$ws_worker->onMessage = function($connection, $data)
{
// 向客户端发送hello $data
$connection->send('hello ' . $data);
};

// 运行worker
Worker::runAll()

前端测试

前端测试例子代码 直接在Google浏览器执行

1
2
3
4
5
6
7
8
9
ws = new WebSocket("ws://127.0.0.1:2000");
ws.onopen = function() {
alert("连接成功");
ws.send('tom');
alert("给服务端发送一个字符串:tom");
};
ws.onmessage = function(e) {
alert("收到服务端的消息:" + e.data);
};

效果展示

执行界面.png
执行界面.png
服务端界面.png
服务端界面.png

Workermen框架支持的协议

1
2
3
4
5
6
7
8
9
10
11
$websocket_worker = new Worker('websocket://0.0.0.0:2345');
// text协议
$text_worker = new Worker('text://0.0.0.0:2346');
// frame协议
$frame_worker = new Worker('frame://0.0.0.0:2347');
// tcp Worker,直接基于socket传输,不使用任何应用层协议
$tcp_worker = new Worker('tcp://0.0.0.0:2348');
// udp Worker,不使用任何应用层协议
$udp_worker = new Worker('udp://0.0.0.0:2349');
// unix domain Worker,不使用任何应用层协议
$unix_worker = new Worker('unix:///tmp/wm.sock');

整合ThinkPHP

说明

Workermen是一个成熟的单独框架,在ThinkPHP中也可以使用Composer安装对应的扩展来使用,这里使用了针对PHP开发的扩展 PHPSocket.IO。
PHPSocket.IO设计的目标是利用PHP构建能够在不同浏览器和移动设备上良好运行的实时应用,如实时分析系统、在线聊天室、在线客服系统、评论系统、WebIM等。 PHPSocket.IO与workerman的区别是,PHPSocket.IO基于workerman开发,workerman有的特性PHPSocket.IO都支持。 PHPSocket.IO最大的优势是对各种浏览器的兼容性更好。

安装及引用

使用Composer 安装对应的扩展

1
composer require workerman/phpsocket.io

在编辑代码时引用对应的扩展即可

1
2
use Workerman\Worker;
use PHPSocketIO\SocketIO;

服务端

创建一个服务端 application\socketio\controller\server.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
namespace app\socketio\controller;

use Workerman\Worker;
use PHPSocketIO\SocketIO;
use think\Db;

class Server{
public function index(){
// 在2021端口创建服务
$io = new SocketIO(2021);
$io->on('connection', function($socket)use($io){
$socket->on('chat message', function($msg)use($io){
$io->emit('chat message', $msg);
});
// 监听到新的客户端连接即在服务端输出'new connection'
echo 'new connection'."\n";
// 并向服务端发送'连接成功'
$socket->emit('success', '连接成功');
// 服务端发送消息过来
$socket->on('sendMsg', function($msg)use($io){
// 在服务端输出消息
echo $msg."\n";
// 在收到的消息前面拼接'收到'后向客户端发送回去
$io->emit('sendMsg', '收到"'.$msg.'"');
});
});
// 启动服务
Worker::runAll();
}
}

由于 Workermen 是一个独立于PHP程序使用的单一文件,需要单独用一个命令行来启动的,他完全可以独立使用,因此并不推荐使用TP框架来整合,但如果有这个需求,也可以在 /public目录下生成一个文件来绑定控制器,例如绑定 到 socketio/Server
创建文件 public/server.php , 输入以下内容

1
2
3
4
5
6
7
8
9
<?php
// [ 应用入口文件 ]
namespace think;

// 加载基础文件
require __DIR__ . '/../thinkphp/base.php';

// 执行应用并响应(绑定)
Container::get('app')->bind('socketio/Server')->run()->send();

执行时 直接在Shell中运行该PHP文件即可,剩下的交给TP的机制

1
2
cd /public
php server.php

执行结果.png
执行结果.png

结语

根据通信行为可以衍生出各类应用,目前websocket已经是各大公司都需要的技术,会websocket就多了一份机会!