websocket

{% note warning no-icon %}
  随着网际网络的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的完善,WebSocket协议被提出,它实现了浏览器与服务器的全双工通讯,扩充套件了浏览器与服务端的通讯功能,使服务端也能主动向客户端传送资料。

介绍

  • WebSocket 是一种标准协议,用于在客户端和服务端之间进行双向数据传输。但它跟 HTTP 没什么关系,它是基于 TCP 的一种独立实现。是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
  • WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
  • 在HTTP协议中,客户端与服务器端的通信是靠客户端发起请求,然后服务器端收到请求再进行回应,这个过程中,客户端是主动的,服务器端是被动的。 而Websocket协议就不一样了,它是基于TCP的一种新的网络协议,它与Http协议不同之处就在于Websocket能实现服务器端主动推送消息到客户端,服务器端与客户端都能发起通信,这一次,服务器端终于也拥有了主动权。
  • 简单概括:WebSocket 是基于TCP的长连接协议,只有一个通信状态不做数据传输,属于应用层协议。

浏览器支持

应用场景

  • 带有实时通讯、实时资料、订阅推送等功能的应用。

为什么要使用 WebSocket

  • 因为HTTP1.0的生命周期是以request作为界定的,也就是一个request,一个response,对于HTTP来说,本次client与server的会话到此结束;而在HTTP1.1中,稍微有所改进,即添加了keep-alive,也就是在一个HTTP连接中可以进行多个request请求和多个response接受操作。
  • 然而在实时通信中,并没有多大的作用,HTTP只能由client发起请求,server才能返回信息,即server不能主动向client推送信息,无法满足实时通信的要求。
WebSocket HTTP
通信方向 双向:但是第一次必须由客户端发起 单向:只能由客户端发送
连接周期 不会断开,可以一直通信。 每完成一次通信就会断开

WebSocket、轮询、Comet比较

  • 在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。
  • 轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端传送请求,频繁地查询是否有新的资料改动。
  • Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些资料设定过期时间,当资料过期后才会向服务端传送请求;这种机制适合资料的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的视窗与服务端建立一个HTTP长连线,服务端会不断更新连线状态以保持HTTP长连线存活;这样的话,服务端就可以通过这条长连线主动将资料传送给客户端;流技术在大并发环境下,可能会考验到服务端的效能。
  • 由于这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。若客户端想知道服务端的处理进度,不需不停的向服务端发送请求,明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。

  • 而当服务器完成协议升级后( HTTP -> WebSocket ),WebSocket可以进行持久化连接,即client只需进行一次握手,成功后即可持续进行数据通信,值得关注的是WebSocket实现client与server之间全双工通信,即server端有数据更新时可以主动推送给client端。解决了轮询造成的同步延迟问题。而且 WebSocket 只需要一次 HTTP 握手,服务端就能一直与客户端保持通信,直到关闭连接,这样就解决了服务器需要反复解析 HTTP 协议的问题,减少了资源的开销。

连接原理

  • HTML5推出的WebSocket,真正实现了Web的实时通讯,使B/S模式具备了C/S模式的实时通讯能力。
  • WebSocket的原理是这样的:浏览器通过JavaScript向服务端发出建立WebSocket连线的请求,在WebSocket连线建立成功后,客户端和服务端就可以通过TCP连线传输资料。因为WebSocket连线本质上是TCP连线,不需要每次传输都带上重复的头部资料,所以它的资料传输量比轮询和Comet技术小了很多。

工作流程

  • 客户端client准备向服务端发送Handshake Request
  • client建立WebSocket时向服务器端请求的信息
  • 服务器获取到client请求的信息后,根据WebSocket协议对数据进行处理并返回,其中要对Sec-WebSocket-Key进行加密等操作。
  • 服务端server向客户端返回Hanshake Response
  • 通信建立完成,进行全双工通信(系统允许二台装置间同时进行双向资料传输。)。
  • 完成通信后客户端client可以向服务端发送Close Connection

程序实作

前端建立与监听

// 创建websocket
var ws = new WebSocket("wss://域名+端口");//[http时为ws://][https时为wss://]
// websocket 创建成功事件
ws.onopen = function (evt) {
  console.log("系统消息:建立连接成功");
};
// websocket 关闭事件
ws.onclose = function (evt) {
  console.log("系统消息:关闭连接成功");
};
// websocket 接收到消息事件
ws.onmessage = function (e) {
  var data = JSON.parse(e.data);
  switch (data.type) {
    case 'handShake':
      //do something
      break;
    case 'login':
      //do something
      break;
    case 'logout':
      //do something
      break;
    case 'user':
      //do something
      break;
    case 'system':
      //do something
      break;
      ......
  }
};
// websocket 错误事件
ws.onerror = function (evt, e) {
  alert("系统消息: 出错了,请退出重试。");
};
// websocket 发送事件
ws.send(data);
//$(document).ready(function(){
  //console.log(websocket.readyState ? `${websocket.readyState}:连接success` : `${websocket.readyState}:连接ing`);//查看websocket readySate
//});

后端建立服务

  • 原生php实践较为复杂,此处采用swoole插件简单介绍

Swoole

  • PHP的socket扩展是一套socket api,仅此而已。
  • Swoole,用C语言实现,它的socket是C 库的socket,更加底层可控。
  • 原生php socket实践较为复杂,而使用swoole扩展可以省去很多步骤如:握手、编码、解码等等,并且简化了广播等操作,所以此处采用swoole插件简单介绍。
  • Swoole 扩展是按照 PHP 标准扩展构建的。使用 phpize 来生成编译检测脚本,./configure 来做编译配置检测,make 进行编译,make install 进行安装。(如无特殊需求,请务必编译安装 Swoole 的最新 release 版本。)
注意事项
  • 如果当前用户不是 root,可能没有 PHP 安装目录的写权限,安装时需要 sudo 或者 su
  • 如果是在 git 分支上直接 git pull 更新代码,重新编译前务必要执行 make clean
  • 仅支持 Linux(2.3.32 以上内核)、FreeBSD、MacOS 三种操作系统,低版本 Linux 系统(如 CentOS 6)可以使用 RedHat 提供的 devtools 编译,参考文档, 在 Windows 平台,可使用 CygWin 或 WSL(Windows Subsystem for Linux)
  • 部分扩展与 Swoole 扩展不兼容,参考 扩展冲突
安装准备
  • php-7.1 或更高版本
  • gcc-4.8 或更高版本
  • make
  • autoconf
安装方法(源码编译安装)
  • 下载源代码包
https://github.com/swoole/swoole-src/releases
https://pecl.php.net/package/swoole
https://gitee.com/swoole/swoole/tags
  • 在终端进入源码目录,执行下面的命令进行编译和安装。
//ubuntu 没有安装 phpize 可执行命令:sudo apt-get install php-dev 来安装 phpize
cd swoole-src && \
phpize && \
./configure && \
make && sudo make install
  • 启用扩展

编译安装到系统成功后,需要在 php.ini 中加入一行 extension=swoole.so 来启用 Swoole 扩展。

安装方法(PECL,注意: PECL 发布时间晚于 Github 发布时间)
  • 执行以下代码
pecl install swoole
  • 添加 Swoole 到 php.ini

修改 php.ini 加入 extension=swoole.so

代码范例

具体参数可查看 swoole 方法参数文档

//创建websocket 服务器
$ws = new swoole_websocket_server(域名, 端口);

//open 建立连接 $ws 服务器,$request:客户端信息
$ws->on('open', function($ws, $request) {
  var_dump($request);
  //do something
  $ws->push($request->fd, "welcome to mychatroom \n");
});

//message 接收信息
$ws->on('message', function($ws, $request) {
  echo "message: $request->data";
  //do something
  $ws->push($request->fd, "get it message \n");
});

//close 关闭连接
$ws->on('close', function($ws, $request) {
  //do something
  echo "close \n";
});

//启动服务
$ws->start();

WebSocket 速查

WebSocket 对象

var Socket = new WebSocket(url, [protocol] );

以上代码中的第一个参数url, 指定连接的 URL。第二个参数protocol是可选的,指定了可接受的子协议。

WebSocket 属性

以下是 WebSocket 对象的属性。

属性描述
Socket.readyState

只读属性readyState表示连接状态,可以是以下值:

  • 0-表示连接尚未建立。

  • 1-表示连接已建立,可以进行通信。

  • 2-表示连接正在进行关闭。

  • 3-表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount

只读属性bufferedAmount已被send()放入正在队列中等待传输,但是还没有发出的UTF-8文本字节数。

WebSocket 事件

以下是 WebSocket 对象的相关事件。

事件事件处理程序描述
openSocket.onopen连接建立时触发
messageSocket.onmessage客户端接收服务端数据时触发
errorSocket.onerror通信发生错误时触发
closeSocket.onclose连接关闭时触发

WebSocket 方法

以下是 WebSocket 对象的相关方法。

方法描述
Socket.send()

使用连接发送数据

Socket.close()

关闭连接

监听websocket事件

Websocket.addEventListener('open',function(event){
  //do something
});

其他

posted @ 2023-09-28 11:29  pandaoh  阅读(14)  评论(0编辑  收藏  举报