WebSocket 协议简介

一、什么是WebSocket

WebSocket是一种在单个TCP连接上进行全双工通讯的协议。
WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。所有浏览器都已经支持了。

二、为什么需要WebSocket

相对于HTTP协议,只能由客户端发起,WebSocket协议允许服务器主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种,使得客户端和服务器之间的数据交换变得更加简单。
现在,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

而比较新的技术去做轮询的效果是Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。

在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

三、http和WebSocket 关系

http和WebSocket都是建立在TCP协议之上的。
WebSocket是基于Http协议的,或者说借用了Http协议来完成一部分握手,在握手阶段与Http是相同的。
这里写图片描述
实例:
一个典型的Websocket握手请求如下:

客户端请求

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13

服务器回应

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/

扫描二维码关注公众号,回复: 2385013 查看本文章

字段说明

Connection必须设置Upgrade,表示客户端希望连接升级。
Upgrade字段必须设置Websocket,表示希望升级到Websocket协议。即告诉Apache、Nginx等服务器,发起的是Websocket协议
Sec-WebSocket-Key是随机的字符串,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个特殊字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算SHA-1摘要,之后进行BASE-64编码,将结果做为“Sec-WebSocket-Accept”头的值,返回给客户端。如此操作,可以尽量避免普通HTTP请求被误认为Websocket协议。
Sec-WebSocket-Version
表示支持的Websocket版本。RFC6455要求使用的版本是13,之前草案的版本均应当弃用。
Origin字段是可选的,通常用来表示在浏览器中发起此Websocket连接所在的页面,类似于Referer。但是,与Referer不同的是,Origin只包含了协议和主机名称。
其他一些定义在HTTP协议中的字段,如Cookie等,也可以在Websocket中使用。
在以前 HTTP 协议中所谓的 keep-alive connection 是指在一次 TCP 连接中完成多个 HTTP 请求,但是对每个请求仍然要单独发 header;它们建立的“长连接”都是伪.长连接,只不过好处是不需要对现有的 HTTP server 和浏览器架构做修改就能实现。
WebSocket 解决的第一个问题是,通过第一个 HTTP request 建立了 TCP 连接之后,之后的交换数据都不需要再发 HTTP request了,使得这个长连接变成了一个真.长连接。但是不需要发送 HTTP header就能交换数据显然和原有的 HTTP 协议是有区别的,所以它需要对服务器和客户端都进行升级才能实现。

四、WebSocket 用法

以PHP为例:
比较简单的实现方式,安装SWOOLE扩展。借用官网(https://wiki.swoole.com/wiki/page/397.html),
服务端代码
websocket.php

$server = new swoole_websocket_server("0.0.0.0", 9501);

$server->on('open', function (swoole_websocket_server $server, $request) {
    echo "server: handshake success with fd{$request->fd}\n";
});

$server->on('message', function (swoole_websocket_server $server, $frame) {
    echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
    $server->push($frame->fd, "this is server");
});

$server->on('close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});

$server->start();

启动

 php websocket.php  start

客户端代码:
https://www.kancloud.cn/yujc/swoole_note/383915

<html>
<head>
  <title></title>
  <meta charset="UTF-8">
  <script type="text/javascript">
  socket = new WebSocket('ws://服务器IP:9501/'); 
socket.onopen = function(evt) { 
    // 发送一个初始化消息
    socket.send('I am the client and I\'m listening!'); 
}; 

// 监听消息
socket.onmessage = function(event) { 
    console.log('Client received a message', event); 
}; 

// 监听Socket的关闭
socket.onclose = function(event) { 
    console.log('Client notified socket has closed',event); 
}; 

socket.onerror = function(evt) { 
    console.log('Client onerror',event); 
}; 

  </script>
</head>
<body>
<button  onclick="socket.send('我发信了')">发送</button>
</body>
</html>

点击“发送”,查看服务器信息,出现以下信息表示成功
这里写图片描述

参考文献
http://www.ruanyifeng.com/blog/2017/05/websocket.html
https://zh.wikipedia.org/wiki/WebSocket
https://wiki.swoole.com/wiki/page/479.html

猜你喜欢

转载自blog.csdn.net/guyan0319/article/details/79400419
今日推荐