环境
php5.6+
swoole扩展
需求
实现简单的广播, 支持身份验证
源码
废话少说,上代码.
<?php
namespace church;
use ReflectionClass;
use ReflectionException;
use Swoole\Websocket\Server;
class WebSocket
{
public $host;
public $port;
public $config;
public $beforeAuthCallback = '';
public $afterAuthCallback = '';
public $beforeSendMsgCallback = '';
public $afterSendMsgCallback = '';
public $authenticator = '';
public $customers = [];
protected $server;
public function __construct($host = '0.0.0.0', $port = 9501, $config = [])
{
$this->host = $host;
$this->port = $port;
$this->config = $config;
$this->init();
}
public function init()
{
$this->server = new Server($this->host, $this->port);
!empty($this->config) && $this->server->set($this->config);
$this->beforeSendMsgCallback = function() {};
$this->afterSendMsgCallback = function() {};
$this->beforeAuthCallback = function() {};
$this->afterAuthCallback = function() {};
$this->authenticator = function() {};
$this->bindEvents();
}
public function bindEvents()
{
$this->server->on('open', [$this, 'onOpen']);
$this->server->on('message', [$this, 'onMessage']);
$this->server->on('close', [$this, 'onClose']);
}
public function run()
{
$this->server->start();
}
public function onOpen(Server $server, $request)
{
call_user_func($this->beforeAuthCallback, $server, $request);
if (!$this->auth($request)) {
return;
}
$this->customers[] = $request->fd;
call_user_func($this->afterAuthCallback, $server, $request);
}
public function onMessage(Server $server, $frame)
{
call_user_func($this->beforeSendMsgCallback, $server, $frame);
$this->broadcast($frame->fd, $frame->data);
call_user_func($this->afterSendMsgCallback, $server, $frame);
}
public function onClose($ser, $fd)
{
$key = array_search($fd, $this->customers);
unset($this->customers[$key]);
}
public function __call($method, $params)
{
$class_name = get_class($this->server);
$class = new ReflectionClass($class_name);
try {
$class->getMethod($method);
} catch (ReflectionException $e) {
echo "Method $method is not exists\n";
return;
}
call_user_func_array([$this->server, $method], $params);
}
public function broadcast($fromUser, $messages)
{
$users = array_diff($this->customers, [$fromUser]);
foreach ($users as $user)
{
$this->server->push($user, $messages);
}
}
private function auth($request)
{
if (($result = call_user_func($this->authenticator, $request)) === false) {
$this->server->push($request->fd, "auth failed");
$this->server->close($request->fd);
}
return $result;
}
}
使用实例
<?php
require './vendor/autoload.php';
use church\WebSocket;
$server = new WebSocket('0.0.0.0', 9501, [
'daemonize' => 1,
]);
$server->authenticator = function($request) use ($server) {
$get = $request->get;
return empty($get) || ($get['access_token'] == 'access_token');
};
$server->afterAuthCallback = function($ser, $request) use ($server) {
$server->push($request->fd, "auth successful");
};
$server->run();
php index.php #就会以守护进程方式运行
客户端js代码:
var websocket = new WebSocket("ws://192.168.2.106:9501?access_token=access_token");
websocket.onopen=function(evt) {
};
websocket.onmessage = function(evt) {
console.log(evt);
};
websocket.onclose = function(evt) {
console.log(evt);
};
搭建过程非常方便。实现的比较简陋,但是可以满足一般的需求了。支持身份验证功能,验证不通过会自动踢掉。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。