WebSocket 协议以及 Socket 接口

目录

前言

一、websocket 协议

1、使用 websocket 协议请求过程解析

2、创建一个 WebSocket 对象

3、WebSocket 的实例方法 和 WebSocket 的事件

(1)、WebSocket 的实例方法

(2)、WebSocket 事件

3、WebSocket 协议与 HTTP 协议的区别

4、WebSocket 与 Socket 的关系

二、Socket

1、客户端-应用层实现心跳包机制

(1)、应用层的心跳包机制

(2)、心跳检测步骤

(3)、心跳检测的优缺点

2、服务端-传输层 TCP 的 KeepAlive 保活机制

(1)、传输层 TCP 的 KeepAlive 保活机制

(2)、KeepAlive 优缺点

3、案例

三、TCP 协议

1、传输控制协议(TCP)

2、TCP保活的必要性

3、TCP 长连接与短连接

(1)、短连接

(2)、长连接


前言

在项目开发时,我们经常需要与服务器进行持续的通讯以保持双方信息的同步。通常这种持久通讯在不刷新页面的情况下进行,消耗一定的内存资源常驻后台,并且对于用户不可见。就聊天的功能来说,我们有以下解决方案:

  • 轮询:
    • 定时轮询:通过 Ajax 轮询请求,每隔一秒或者一段时间请求一次服务器查看是否有未读消息。
    • 长轮询:每一个请求发送到服务器时,服务器将请求卡主,直到有消息时才返回。
  • 使用 WebSocket 协议(推荐)

由于轮询存在明显的弊端:占用服务端地资源, 增大服务端压力,会产生很多无效请求,而且消息存在延时性。所以,推荐使用 WebSocket 协议代替轮询来做即时的、持续的通讯。

WebSocket 协议以及 Socket 接口_第1张图片

一、websocket 协议

推荐一款 在线WebSocket调试 工具。

推荐一个基于 websocket 协议的用来提供持续通信的库——Socket.IO。

WebSocket API 是 HTML5 标准的一部分, 但这并不代表 WebSocket 一定要用在 HTML 中,或者只能在基于浏览器的应用程序中使用。 

websocket 是一个基于应用层的网络协议,建立在 TCP 协议之上,和 HTTP 协议可以说是兄弟的关系。我们会先用 HTTP 先进行三次握手,再向服务器请求升级为websocket 协议。

WebSocket 协议将 TCP 的 Socket(套接字)应用在了 web page 上,从而使通信双方建立起一个保持在活动状态连接通道,并且属于全双工(双方同时进行双向通信)。

WebSocket 协议是借用  HTTP 协议 的 101 switch protocol 来达到协议转换的,从 HTTP 协议切换成 WebSocket 通信协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话。

1、使用 websocket 协议请求过程解析

连接过程 —— 握手过程:

  • 浏览器、服务器建立 TCP 连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。
  • TCP 连接成功后,浏览器通过 HTTP 协议向服务器传送 WebSocket 支持的版本号等信息。(开始前的 HTTP 握手)
  • 服务器收到客户端的握手请求后,同样采用 HTTP 协议回馈数据。
  • 当收到了连接成功的消息后,通过 TCP 通道进行传输通信。

WebSocket 协议以及 Socket 接口_第2张图片

只需要一次握手,就可以建立持久连接。为了建立一个 WebSocket 连接,浏览器需要向服务器发送一个 HTTP 请求,这个请求和普通的 HTTP 请求不同。请求头中需要附加 Upgrade: WebSocket。这样表示这是一个申请协议升级的 HTTP 请求。其中:

  • Upgrade 和 Connection 字段:告诉服务端,发起的是 webSocket 协议。
  • Sec-WebSocket-Key 字段:是浏览器经过 Base64 加密后的密钥,用来和 response 里面的Sec-WebSocket-Accept进行比对验证。
  • Sec-WebSocket-Version 字段:是当前的协议版本。
  • Sec-WebSocket-Extensions 字段:是对 WebSocket 的协议扩展。
GET /spring-WebSocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: WebSocket 
Connection: Upgrade 
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080

服务器解析对应的请求头进行响应。其中:

  • Upgrade 和 Connection 字段:告诉浏览器,服务已经是基于 webSocket 协议的了,让浏览器也遵循这个协议
  • Sec-WebSocket-Accept 字段:服务端确认后并加密后的 Sec-WebSocket-Accept。
HTTP/1.1 101 Switching Protocols 
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp

成功响应的状态码为 101,同样也有 Upgrade 表示服务器同意协议升级。成功握手后,HTTP 升级请求底层的 TCP 套接字保持打开状态,客户端和服务器都可以继续发送和接收消息。

请求消息中 Sec-WebSocket-Key 是随机的,服务器会用这些数据构造出一个 SHA-1 的信息摘要,把 Sec-WebSocket-Key 加上一个魔幻字符串。使用 SHA-1 加密,然后进行 BASE-64 编码,结果做为 Sec-WebSocket-Accept 头的值,返回给客户端。

2、创建一个 WebSocket 对象

var ws = new WebSocket('ws://echo.websocket.org');

3、WebSocket 的实例方法 和 WebSocket 的事件

(1)、WebSocket 的实例方法

WebSocket 方法 描述
ws.send() 使用连接发送数据
ws.close() 关闭链接

(2)、WebSocket 事件

WebSocket 事件 描述
open  连接建立时触发。
message  客户端接收服务端数据时触发。
error  通信发生错误时触发。

close 

连接关闭时触发。

例如:

ws.onopen = function(e) { 
  console.log("Connection open ..."); 
  ws.send("Hello WebSockets!");
};

ws.onmessage = function(e) {
  console.log( "Received Message: " + e.data);
  ws.close();
};

ws.onerror = function(e) {
  console.log("error!!!"); 
};

ws.onclose = function(e) {
  console.log("Connection closed.");
}; 

当然也可以使用 addEventListener 方法添加事件监听,使用 addEventListener 方法添加事件监听时需要把方法名去掉 on。例如:

ws.addEventListener('open', function (event) {
  ws.send('Hello Server!');
});

3、WebSocket 协议与 HTTP 协议的区别

相同点:

  • 都是基于 TCP 的可靠性传输协议。
  • 都工作在应用层。

不同点:

  • WebSocket 协议:
    • 客户端和服务器只需要一次握手,就可以建立持久连接。
    • 全双工(双向的)通信:客户端和服务器都能主动的向对方发送或接收数据。
    • WebSocket 在建立握手时,数据是通过 HTTP 传输的。但是建立之后,是不需要 HTTP 协议的。建立了 WebSocket 之后服务器不必在浏览器发送 request 请求之后才能发送信息到浏览器,服务器可以主动向浏览器发送数据,而且信息当中不必再带有 head 的部分信息了。与 HTTP 的长链接通信相比,这种方式,不仅能降低服务器的压力,而且信息当中也减少了部分多余的信息,节省了带宽。
  • HTTP 协议:
    • 无状态:对于历史连接是完全没有记忆的, 每一次连接都是新的连接。
    • 无连接、非持久化:一次请求, 一次响应, 不会持续。
    • 半双工(单向的)通信:通信请求只能由客户端发起, 服务端只能对于请求做出应答, 服务端不能主动地向客户端发送数据。
    • HTTP 链接分为短链接,长链接,短链接是每次请求都要三次握手才能发送自己的信息。即每一个 Request 对应一个 Response。长链接是在一定的期限内保持 TCP 连接不断开。

4、WebSocket 与 Socket 的关系

WebSocket 是一个协议。Socket(套接字)是一组接口而不是一个协议,Socket 是为了方便使用 TCP 或 UDP 而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。

二、Socket

1、客户端-应用层实现心跳包机制

Socket 保活指的是:Socket 保持长链接。

常见的 Socket 保活有两种方案:服务端传输层 TCP 的 KeepAlive 保活机制 客户端应用层实现心跳包机制

(1)、应用层的心跳包机制

跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。

在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。

心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。

其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。

在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。

总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。

(2)、心跳检测步骤

  • 客户端每隔一个时间间隔发生一个探测包给服务器
  • 客户端发包时启动一个超时定时器
  • 服务器端接收到检测包,应该回应一个包
  • 如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器
  • 如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了

(3)、心跳检测的优缺点

优点:

  • 最大的有点就是自己实现检测机制带来的灵活性。
  • 我们可以做很多事情:控制检测时机,间隔和处理流程。还可以在发出的心跳包中加入额外信息。可以避免上面所说tcp keepalive的缺点。可以检测连接存在,还可以检测连接可用。
  • 还有就是通用性,当传输层使用的是udp的时候,我们socket编程也不需要改变很多代码。socket为我们提供了tcp和udp编程。

缺点:

  • 需要应用层自己实现。自己利用 socket 编程实现。

2、服务端-传输层 TCP 的 KeepAlive 保活机制

(1)、传输层 TCP 的 KeepAlive 保活机制

因为要考虑到一个服务器通常会连接多个客户端,因此由用户在应用层自己实现心跳包,代码较多 且稍显复杂,而利用TCP/IP协议层为内置的KeepAlive功能来实现心跳功能则简单得多。

不论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。 因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不开启KeepAlive功 能,尽管这微不足道,但在按流量计费的环境下增加了费用。另一方面,KeepAlive设置不合理时可能会 因为短暂的网络波动而断开健康的TCP连接。并且,默认的KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多服务端应用程序来说,2小时的空闲时间太长。因此,我们需要手工开启KeepAlive功能并设置合理的KeepAlive参数。

(2)、KeepAlive 优缺点

优点:

  • 使用简单,tcp协议提供的检活(发送探测包 ack包)。

缺点:

  • KEEPALIVE的目的是探测连接是否存在,无法检测能不能发送数据,比如服务器由于负载过大到处无法响应请求,应用层的的原因导致数据无法传输,但是连接还是正常。
  • 如果TCP连接的一端断网或者断电,应用层并不知晓,继续发送数据,这个数据包的优先级是高于KEEPALIVE的数据包,因此这个KEEPALIVE包是无法发送出去的,只有在长时间的重传失败后,我们才能判断连接断开,这段长时间,应用及其容易产生业务逻辑BUG。

3、案例

理解WebSocket心跳及重连机制(五)

js socket心跳链接及断线重连处理

websocket心跳及重连机制

三、TCP 协议

1、传输控制协议(TCP)

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次握手的,而释放则需要4次握手,所以说每个连接的建立都是需要资源消耗和时间消耗的。

2、TCP保活的必要性

TCP 的长连接理论上只要连接建立后,就会一直保持着。但有时有一些防火墙之类的软件会自动检查主机的网络连接状况,比如说如果发现某个连接在几分钟之内都没有数据通讯,则会关闭这个连接。有时客户端与服务器需要实时的检测连接状态,就是需要知道对方是否还在线,如果对方不在线了,需要做相应的处理,这是就需要通过发送心跳包的方法监测链路的状态。

3、TCP 长连接与短连接

(1)、短连接

我们模拟一下 TCP 短连接的情况,client向server发起连接请求,server接到请求,然后双方建立连接。client向server发送消息,server回应client,然后一次读写就完成了,这时候双方任何一个都可以发起close操作,不过一般都是client先发起close操作。为什么呢,一般的server不会回复完client后立即关闭连接的,当然不排除有特殊的情况。从上面的描述看,短连接一般只会在client/server间传递一次读写操作

短连接的优点是:管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段。

(2)、长连接

接下来我们再模拟一下长连接的情况,client向server发起连接,server接受client连接,双方建立连接。Client与server完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。

首先说一下TCP/IP详解上讲到的TCP保活功能,保活功能主要为服务器应用提供,服务器应用希望知道客户主机是否崩溃,从而可以代表客户使用资源。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务器端检测到这种半开放的连接。

【本文参考】

【分布式WebSocket - 1】超详细!WebSocket协议详解

websocket和http的瓜葛以及websocket协议实现

websocket深入浅出

WebSocket介绍和Socket的区别

TCP连接 保持 保活
socket保活方案 Tcp KeepAlive和应用层HeartBeat
Socket如何保证长连接

你可能感兴趣的:(计算机与网络,websocket,协议,Socket,接口,TCP,协议的长链接)