HTML WebSocket

前言

  • WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

1、WebSocket

  • HTML5 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

  • 在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

  • 现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

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

  • 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

  • 在使用 WebSocket 之前,需检测用户的浏览器是否支持它。

    1
    2
    3
    4
    5
    6
    7
    8
    <script>
    if ("WebSocket" in window) {
    // 是的! WebSocket 支持!
    // 一些代码.....
    } else {
    // 抱歉! WebSocket 不支持
    }
    </script>

2、创建 WebSocket 连接

  • 以下 API 用于创建 WebSocket 连接。获取 Web Socket 连接后,可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

    1
    var Socket = new WebSocket(url, [protocol]);
  • 以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。

2.1 资源标志符

  • Websocket 的 url 使用 ws 或 wss 的统一资源标志符,类似于 https,其中 wss 表示在 TLS 之上的 Websocket。

    1
    2
    ws://example.com/wsapi
    wss://secure.example.com/
  • Websocket 使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Websocket 协议使用 80 端口;运行在 TLS 之上时,默认使用 443 端口。

2.2 握手请求

  • WebSocket 协议本质上是一个基于 TCP 的协议。

  • 为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息 “Upgrade: WebSocket” 表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。

  • 一个典型的 Websocket 握手请求如下:

  • 客户端请求

    1
    2
    3
    4
    5
    6
    7
    GET / HTTP/1.1
    Upgrade: websocket
    Connection: Upgrade
    Host: example.com
    Origin: http://example.com
    Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
    Sec-WebSocket-Version: 13
  • 服务器回应

    1
    2
    3
    4
    5
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
    Sec-WebSocket-Location: ws://example.com/
  • Connection 必须设置 Upgrade,表示客户端希望连接升级。

  • Upgrade 字段必须设置 Websocket,表示希望升级到 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 中使用。

2.3 websocket 服务器

3、属性

  • 以下是 WebSocket 对象的属性。










属性描述
Socket.readyState只读属性 readyState 表示连接状态,可以是以下值:
    0 - 表示连接尚未建立。
    1 - 表示连接已建立,可以进行通信。
    2 - 表示连接正在进行关闭。
    3 - 表示连接已经关闭或者连接不能打开。
Socket.bufferedAmount只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

4、事件

  • 以下是 WebSocket 对象的相关事件。
事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发

5、方法

  • 以下是 WebSocket 对象的相关方法。
方法 描述
Socket.send() 使用连接发送数据
Socket.close() 关闭连接

6、实例

6.1 客户端的 HTML 和 JavaScript

  • websocket.html 文件内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <button onclick="startWebSocket()">运行 WebSocket</button>
    <button onclick="closeWebSocket()">关闭 WebSocket</button> <br />
    <p>接收到的数据:<output id="result"></output></p>

    <script>
    var socket;

    function startWebSocket() {
    if ("WebSocket" in window) {
    alert("您的浏览器支持 WebSocket!");

    // 打开一个 web socket
    socket = new WebSocket("ws://localhost:9998/echo");

    socket.onopen = function () {
    // Web Socket 已连接上,使用 send() 方法发送数据
    socket.send("发送数据");
    alert("数据发送中...");
    };
    socket.onmessage = function (evt) {
    var received_msg = evt.data;
    document.getElementById("result").innerHTML += "<br />" + event.data;
    alert("数据已接收...");
    };
    socket.onclose = function () {
    alert("连接已关闭...");
    };
    } else {
    alert("您的浏览器不支持 WebSocket!");
    }
    }

    function closeWebSocket() {
    // 关闭 websocket
    socket.close();
    }
    </script>

6.2 服务端 WebSocket 的服务

  • 在执行以上程序前,需要创建一个支持 WebSocket 的服务。从 pywebsocket 下载 mod_pywebsocket,或者使用 git 命令下载。

    1
    $ git clone https://github.com/googlearchive/pywebsocket
  • mod_pywebsocket 是一个 Apache HTTP 的 Web Socket 扩展,需要 python 环境支持。

  • 解压下载的文件。进入 pywebsocket 目录。执行以下命令。

    1
    2
    $ python setup.py build
    $ sudo python setup.py install
  • 查看文档说明。

    1
    $ pydoc mod_pywebsocket
  • 开启服务,在 pywebsocket/mod_pywebsocket 目录下执行以下命令。

    1
    $ sudo python standalone.py -p 9998 -w ../example/
  • 以上命令会开启一个端口号为 9998 的服务,使用 -w 来设置处理程序 echo_wsh.py 所在的目录。

  • 现在就可以在浏览器打开前面创建的 websocket.html 文件。如果浏览器支持 WebSocket(), 点击 “运行 WebSocket”,就可以看到整个流程各个步骤弹出的窗口和接收到的数据了。

  • 效果

7、websocket 与 socket 的区别

  • 软件通信有七层结构,下三层结构偏向与数据通信,上三层更偏向于数据处理,中间的传输层则是连接上三层与下三层之间的桥梁,每一层都做不同的工作,上层协议依赖与下层协议。

  • 基于这个通信结构的概念。Socket 其实并不是一个协议,是应用层与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口。当两台主机通信时,让 Socket 去组织数据,以符合指定的协议。TCP 连接则更依靠于底层的 IP 协议,IP 协议的连接则依赖于链路层等更低层次。

  • WebSocket 则是一个典型的应用层协议。

  • 总的来说:Socket 是传输控制层协议,WebSocket 是应用层协议。

文章目录
  1. 1. 前言
  2. 2. 1、WebSocket
  3. 3. 2、创建 WebSocket 连接
    1. 3.1. 2.1 资源标志符
    2. 3.2. 2.2 握手请求
    3. 3.3. 2.3 websocket 服务器
  4. 4. 3、属性
  5. 5. 4、事件
  6. 6. 5、方法
  7. 7. 6、实例
    1. 7.1. 6.1 客户端的 HTML 和 JavaScript
    2. 7.2. 6.2 服务端 WebSocket 的服务
  8. 8. 7、websocket 与 socket 的区别
隐藏目录