swoole php推送,PHP使用WebSwoole来实现消息推送

本文探讨了如何利用WebSwoole技术在PHP的B/S架构博客系统中实现用户间的实时消息推送,例如评论回复通知。通过WebSocket协议,实现实时双向通信,当用户A的评论被用户B回复时,系统能即时发送提醒给用户A。文章详细介绍了WebSocket的工作原理和在CommentServer类中的关键代码实现。
摘要由CSDN通过智能技术生成

邓绪高

摘要:在一个博客系统中,经常会使用到消息推送系统来发送一些通知给登录用户。如博主需要发送某个消息给所有登录用户,或者某个用户对另一个用户的评论进行了回复等等。该文利用WebSwoole技术来实现点对点的消息推送提醒。

关键词:PHP;WebSwoole;消息推送

中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2018)25-0091-02

1 前言

B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式。这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链接,但不容易直接完成实时的消息推送功能,如聊天室、后台消息提醒、实时更新数据等功能,但通过polling、Long polling、长连接、Flash Socket以及HTML5中定义的WebSocket能完成该功能需要。

1.1 Socket简介

Socket又称“套接字”,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。Socket的英文原义是“孔”或“插座”,作为UNIX的进程通信机制。Socket可以实现应用程序间网络通信。

1.2 WebSocket简介与消息推送

B/S架构的系统多使用HTTP协议,HTTP协议的特点:

1)无状态协议;

2) 用于通过 Internet 发送请求消息和响应消息;

3) 使用端口接收和发送消息,默认为80端口。

底层通信还是使用Socket完成。HTTP协议决定了服务器与客户端之间的连接方式,无法直接实现消息推送。

WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。特点:1)事件驱动;2)异步;3)使用ws或者wss协议的客户端socket。

能够实现真正意义上的推送功能。

1.3 WebSocket客户端

websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。在websocket中有两个方法:

1)send() 向远程服务器发送数据;2)close() 关闭该websocket链接。

websocket同时还定义了几个监听函数:

1)onopen 当网络连接建立时触发该事件;2)onerror 当网络发生错误时触发该事件;3)onclose 当websocket被关闭时触发该事件;4)onmessage 当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件。

websocket的url开头是ws,如果需要ssl加密可以使用wss,当我们调用websocket的构造方法构建一个websocket对象(new WebSocket(url))的之后,就可以进行即时通信了。

2 需求分析

以博客系统中评论被回复为例,当一条评论被其他某个用户(假设是用户B)回复,即发一条通知给被回复的评论所属人(假设是用户A),告诉A,他的评论被回复了。

2.1 功能分析:

1)我们不能保证用户B和用户A都处于连接状态,但是通常情况下,用户B至少是连接状态,用户A不一定跟server保持连接;

2)任一用户都不止对应一个客户端。换言之,用户A和用户B都可能打开了多个tab页,对于一个tab页,就会有一个独立的fd标识,我们这里认为任一用户只有最新的fd有效,或者你可以认为用户所有的tab页的连接都有效;

3)因为没有用户系统,我们以get传递的参数uid为标识,uid=100视为用户A,uid=101视为用户B;

4)我们不准备做一个评论系统,我们模拟的tab页包将会包含一个输入内容的文本框、一个输入目标uid的input和一个发送的按钮以满足需求。

2.2流程分析:

1)户A($_GET['uid'] = 100)在某个tab页的输入框输入“回复xxx的内容”字样后,点击发送。

2)户B($_GET['uid'] = 101)如果处于连接状态,则alert提醒用户B,他的评论被回复了。

3关键代码实现

将WebSwoole的创建和相关的回调封装到一个类中,服务器端代码逻辑如下:

1)我们给CommentServer类增加了一个属性 $user2fd,这个是key => value结构,用于保存uid和fd的映射关系。

2)onOpen回调做两件事,验证授权和添加新的映射关系。

3)onMessage回调只接收含有event项的数组,event等同于CommentServer类的方法名,我们这里只有一个用于web通知的alertTip方法。

此外,我们封装了该类的close方法和push方法,close方法用于server主动关闭连接,删除uid和fd的映射,push方法用于向指定的fd推送消息

class CommentServer

{ private $_serv; //webswoole变量

public $key = '^abc&swoole;$';//token的生成鑰匙

// 用户id和fd对应的映射,key => value,key是用户的uid,value是用户的fd

public $user2fd = [];

public function __construct()

{$this->_serv = new swoole_websocket_server("127.0.0.1", 9501); //创建webswoole

$this->_serv->set([

'worker_num' => 1,

'heartbeat_check_interval' => 60,//心跳检测

'heartbeat_idle_time' => 125,

]);

//绑定回调

$this->_serv->on('open', [$this, 'onOpen']);

$this->_serv->on('message', [$this, 'onMessage']);

$this->_serv->on('close', [$this, 'onClose']);

}

public function onOpen($serv, $request)

{// 连接授权

$accessResult = $this->checkAccess($serv, $request);

if (!$accessResult) {

return false;

}

if (array_key_exists($request->get['uid'], $this->user2fd)) {

始终把用户最新的fd跟uid映射在一起

return false;

} else {

$this->user2fd[$request->get['uid']] = $request->fd;}}

public function onMessage($serv, $frame)

{// 校验数据的有效性,数据被`json_decode`处理之后是数组并且数组的`event`项非空才是有效数据

// 非有效数据,关闭该连接

$data = $frame->data;

$data = json_decode($data, true);

if (非有效数据) {关闭该连接}

// 根据数据的`event`项,判断要做什么,`event`映射到当前类具体的某一个方法,方法不存在则关闭连接

$method = $data['event'];

if (方法不存在) {关闭连接}

$this->$method($frame->fd, $data); }//执行当前类的某个具体方法

//webswoole服务器端在收到客户端数据后要执行的操作

public function alertTip($fd, $data)

{if (推送目标用户的uid非真或者该uid尚无保存的映射fd) {

关闭连接

}

//向目标用户推送消息提醒

$this->push(目标用户, ['event' => $data['event'], 'msg' => '收到一条新的回复.']);

}

public function start()

{

$this->_serv->start();

}}

客户端代码如下CommentClient.php:

发送内容:

发送给谁:

发送

var ws = new WebSocket("ws://127.0.0.1:9501?uid=&token=");

ws.onopen = function(event) {

};

ws.onmessage = function(event) {

var data = event.data;

data = eval("("+data+")");

if (data.event == 'alertTip') { alert(data.msg); }

};

ws.onclose = function(event) { console.log('Client has closed.\n'); };

function send() {

var obj = document.getElementById('content');

var content = obj.value;

var toUid = document.getElementById('toUid').value;

ws.send('{"event":"alertTip", "toUid": '+toUid+'}');}

在浏览器中访问127.0.0.1/commentclient.php?uid=101时,会有两个输入框,一个填写消息推送内容,一个填写目标用户,点击发送,则在线的目标用户能马上收到消息提醒。

4 总结

该消息推送功能是在没有用户系统的情况下实现的,所以只能硬编码了两个用户A和B进行模拟,并且当目标用户B不在线时,他是收不到消息提醒的,如果想在目标用户上线后依然能收到消息提醒,可以先把对A的评论通知存储起来,在用户A连接的时候在进行通知。

参考文献:

[1] Matt Zandstra.深入PHP:面向对象、模式与实践[M].北京:人民邮電出版社,2011.

[2] Yii Framework中文网文档中心[EB/OL].https://www.yiichina.com/doc.

[3] 白狼栈[EB/OL]. http://www.manks.top/.

【通联编辑:张薇】

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值