当前位置: 首页 > news >正文

基于socket.io的实时消息推送

用户访问Web站点的过程是基于HTTP协议的,而HTTP协议的工作模式是:请求-响应,客户端发出访问请求,服务器端以资源数据响应请求。 也就是说,服务器端始终是被动的,即使服务器端的资源数据发生变化,如果没有来自客户端的请求,用户就不会看到这些变化。 这种模式是不适合某些应用场景的,比如在社交网络用户需要近乎实时地知道其他用户最新的信息。对于普通站点来说, 请求-响应模式可以满足绝大多数的功能需求,但总有某些功能我们希望能够为用户提供实时消息的体验。

为解决这个问题,有两种方案可以选择:

  1. 仍旧使用请求-响应模式,只是增大请求的频率或者使用长连接,来达到尽可能接近实时的效果,如使用polling/long-polling,但可能会极大地增加服务器的负载压力或降低服务器的吞吐量
  2. 使用新的协议,在服务器端有资源数据更新时,主动推送给客户端,如WebSocket,虽然这种思路也是使用了长连接,但效率更高,且是客户端服务器端之间的全双工通信。 问题在于目前各大浏览器并不都支持WebSocket。

那么目前最好的方式就是结合以上两种方案,在不同的浏览器中,尽可能使用浏览器支持的最好的方案,即浏览器支持第二种方案时,优先使用第二种方案,否则使用第一种方案。socket.io就是这么做的,并且在服务器端和客户端对于不同的方案提供统一的接口。


在我们产品的站内信功能中,希望能够给在线用户实时推送公共消息或私有消息。考虑到以后可能还有其他功能需要实现实时消息推送,所以将实时消息推送实现为一个单独的服务。这种针对不同特性的功能进行解耦也为之后针对性的优化做了铺垫。

解耦之后的系统结构如下所示:

socket.io-push-server

当站点服务器(A)监测到资源数据更新事件发生时,先将数据推送到消息推送服务器(B),B根据消息的类型以及消息的目标接收人来决定是否推送,如何推送。

由于我们的Web后端是基于Yii框架实现,那么该如何实现A与B的socket.io服务通信呢?socket.io有自己的一套协议,如果自己实现PHP库来与socket.io服务交互,还有一些工作量。最终我们选择elephant.io这个PHP库,并将elephant.io封装为Yii框架的一个组件,实现如下:

<?php

$basePath = Yii::getPathOfAlias('application.vendor.elephantio.lib.ElephantIO'); require_once($basePath . DIRECTORY_SEPARATOR . 'Client.php'); require_once($basePath . DIRECTORY_SEPARATOR . 'Payload.php'); use ElephantIO\Client as Elephant; class extElephantIO extends CApplicationComponent { public $host = null; public $port = null; public $namespace = null; private $elephant = null; private $ioNameSpace = null; public function init() { if ($this->host === null || $this->port === null) { throw new Exception('%s: %s: %s, Please give me parameters host and port', basename( __FILE__ ), __FUNCTION__, __LINE__); } } public function setNameSpace($nameSpace) { if ($this->elephant === null) { $this->elephant = new Elephant('http://' . $this->host . ':' . $this->port, 'socket.io', 1, false, true, true); $this->elephant->init(); } $this->ioNameSpace = $this->elephant->createFrame(null, $nameSpace); } public function sendMsg($event, $msg) { if ($this->ioNameSpace === null) { if 

相关文章:

  • 找规律 UVALive 6506 Padovan Sequence
  • 图书管理系统——测试与调试
  • .net 发送邮件
  • Launch Screen在iOS7/8中的实现
  • Bootstrap系列 -- 17. 复选框checkbox和单选择按钮radio
  • rpm 与 yum 源
  • Linux使用快捷键,who命令,rm命令,ps命令,cd,命令kill命令,find命令,grep命令,tar命令(gz、tar、bz2),用户管理,vim配置的一部分,相关命令...
  • 健康篇之抗生素---对症下药
  • 分布式文件系统MogileFS介绍
  • [20150629]简单的加密连接.txt
  • python 装饰器 一 (简单不带参数的函数)
  • Android SDK开发包国内下载地址
  • 利用JasperReport+iReport进行Web报表开发
  • 如何对数据库中的表以及表中的字段进行重命名
  • HDU 4513 哥几个系列故事——形成完善II manacher求最长回文
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【个人向】《HTTP图解》阅后小结
  • egg(89)--egg之redis的发布和订阅
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Java 网络编程(2):UDP 的使用
  • Java,console输出实时的转向GUI textbox
  • java正则表式的使用
  • JS+CSS实现数字滚动
  • JS学习笔记——闭包
  • Node + FFmpeg 实现Canvas动画导出视频
  • Vue 2.3、2.4 知识点小结
  • Vue ES6 Jade Scss Webpack Gulp
  • 关于字符编码你应该知道的事情
  • 和 || 运算
  • 解决iview多表头动态更改列元素发生的错误
  • 近期前端发展计划
  • 力扣(LeetCode)56
  • 数据科学 第 3 章 11 字符串处理
  • 自制字幕遮挡器
  • 阿里云重庆大学大数据训练营落地分享
  • 树莓派用上kodexplorer也能玩成私有网盘
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (2020)Java后端开发----(面试题和笔试题)
  • (Java)【深基9.例1】选举学生会
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (ZT)薛涌:谈贫说富
  • (论文阅读40-45)图像描述1
  • (三)Honghu Cloud云架构一定时调度平台
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • .NET中统一的存储过程调用方法(收藏)
  • @Not - Empty-Null-Blank
  • [ C++ ] STL_list 使用及其模拟实现
  • [] 与 [[]], -gt 与 > 的比较
  • [2]十道算法题【Java实现】
  • [c#基础]值类型和引用类型的Equals,==的区别
  • [CISCN2021 Quals]upload(PNG-IDAT块嵌入马)