您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
swoole2.2.0+php7.0.19实现websocket的客户端与服务器端
发布时间:2019-07-16 00:36:50编辑:雪饮阅读()
项目中有两处需要用到异步更新状态的逻辑。
第一处就是当动态的收款二维码展示出来的时候用户扫码并支付成功就关闭掉二维码。
第二处是挂单列表,此处要在结算订单之前先将订单发送至静态二维码,并当用户扫码支付后该订单才会出现结算按钮。
这两个逻辑一般第一反应肯定是用ajax进行轮询后端,但这样比较消耗性能,而且锁浏览器。
我打算用websocket实现,在js中websocket现在已经是自带的,据说好像是h5出来以后才正式有的。
对于我们php后端来说可以通过安装swoole扩展实现websocket的服务端,而php的websocket客户端则有点麻烦。
环境:
php7.0.19
安装swoole
由于我有现成的宝塔集成环境,于是直接安装了swoole扩展(安装后是swoole2.2),如果没有宝塔,也可以自己独立编译安装。
websocket服务端的实现
脚本
[root@iz2zeb6y4kyvw5p1zok89pz erp.gaojiupan.cn]# cat socketCli.php
<?php
$ws=new swoole_websocket_server("0.0.0.0",9504);
//监听websocket客户端打开事件
$ws->on('open',function($ws,$request){
//向websocket客户端响应(必须回应)
$ws->push($request->fd,"welcome");
});
//监听websocket服务端接收信息事件
$ws->on('message',function($ws,$request){
$data=json_decode($request->data,true);
if(json_last_error()!=JSON_ERROR_NONE) return;
if(!isset($data['notify'])) return;
if($data['notify']!=1) return;
foreach ($ws->connections as $fd) {
// 需要先判断是否是正确的websocket连接,否则有可能会push失败
if($fd!=$request->fd && $ws->isEstablished($fd)){
$ws->push($fd, $request->data);
}
}
});
//监听客户端关闭连接事件
$ws->on("close",function($ws,$request){
echo "close\n";
});
$ws->start();
?>
启动服务
在这里好像是必须以cli模式启动,该脚本要授权可执行,那么该脚本启动如:
[root@iz2zeb6y4kyvw5p1zok89pz erp.gaojiupan.cn]#php ./ socketCli.php&
php版websocket客户端的实现
由于我们后端监听的是websocket,前端js也是websocket,所以订单推送也必须是一个websocket客户端,订单推送的客户端向websocket服务端推送数据,由websocket服务端向前端的websocket推送。
这里用了swoole框架的局部代码,并且在tp5.0.20上实现的,所以要在其控制器中导入swoole命名空间,这里用的第三方扫呗支付的异步通知局部代码如:
public function saoBeiNotify(){
Log::init(['type' => 'File', 'path' => 'uploads/']);
$data_input=file_get_contents('php://input');
$data=json_decode($data_input,true);
Log::write('saoBeiNotify:','notice');
Log::write($data,'notice');
if($data['result_code']=='01'){
$terminal_trace=$data['terminal_trace'];
Db::startTrans();
try{
$where1['cashiernum']=$terminal_trace;
$id=model('XmCashire')->where($where1)->value('topdid');
model('XmCashire')->where($where1)->update(['saoBeiPay'=>1]);
model('XmDepartment')->where(['id'=>$id])->update(['qr_cashiernum'=>'']);
}
catch(\Exception $e){
Log::write($e,'notice');
Log::write('saoBeiNotifyEnd:','notice');
Db::rollback();
exit();
}
Db::commit();
//websocket通知
require_once '../extend/swooleFramework3.0/websocket.php';
require_once '../extend/swooleFramework3.0/WebSocketParser.php';
require_once '../extend/swooleFramework3.0/Socket.php';
require_once '../extend/swooleFramework3.0/TCP.php';
require_once '../extend/swooleFramework3.0/Parser.php';
$websocket=config('base.websocket');
$host=$websocket['host'];
$port=$websocket['port'];
$client = new Swoole\Client\WebSocket($host,$port);
if(!$client->connect()) return json(['return_code'=>'02','return_msg'=>'success']);
while (true)
{
//1收银处扫呗订单,2短信购买处订单
$data1['type']=1;
$data1['cashiernum']=$terminal_trace;
$data1['notify']=1;
$data1=json_encode($data1);
$client->send($data1);
$message = $client->recv();
if($message) break;
}
return json(['return_code'=>'01','return_msg'=>'success']);
}
}
javascript版websocket的实现
[root@iz2zeb6y4kyvw5p1zok89pz erp.gaojiupan.cn]# cat application/xm/view/Cashier/websocket.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
var wsServer="ws://47.95.227.150:9504";
var websocket=new WebSocket(wsServer);
websocket.onopen=function (evt) {
console.log("连接成功");
}
websocket.onclose=function (evt) {
console.log("关闭");
}
websocket.onmessage=function (evt) {
console.log(evt.data);
}
websocket.onerror=function (evt,e) {
console.log('error');
}
</script>
</head>
<body>
</body>
附件下载
关键字词:swoole2.2,php7.0,websocket