目录
前言
一、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)、长连接
在项目开发时,我们经常需要与服务器进行持续的通讯以保持双方信息的同步。通常这种持久通讯在不刷新页面的情况下进行,消耗一定的内存资源常驻后台,并且对于用户不可见。就聊天的功能来说,我们有以下解决方案:
由于轮询存在明显的弊端:占用服务端地资源, 增大服务端压力,会产生很多无效请求,而且消息存在延时性。所以,推荐使用 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 通信协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话。
连接过程 —— 握手过程:
只需要一次握手,就可以建立持久连接。为了建立一个 WebSocket 连接,浏览器需要向服务器发送一个 HTTP 请求,这个请求和普通的 HTTP 请求不同。请求头中需要附加 Upgrade: WebSocket。这样表示这是一个申请协议升级的 HTTP 请求。其中:
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
服务器解析对应的请求头进行响应。其中:
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 头的值,返回给客户端。
var ws = new WebSocket('ws://echo.websocket.org');
WebSocket 方法 | 描述 |
---|---|
ws.send() | 使用连接发送数据 |
ws.close() | 关闭链接 |
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!');
});
相同点:
不同点:
WebSocket 是一个协议。Socket(套接字)是一组接口而不是一个协议,Socket 是为了方便使用 TCP 或 UDP 而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。
Socket 保活指的是:Socket 保持长链接。
常见的 Socket 保活有两种方案:服务端传输层 TCP 的 KeepAlive 保活机制 和 客户端应用层实现心跳包机制。
跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。
在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。
其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。
在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。
总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。
优点:
缺点:
因为要考虑到一个服务器通常会连接多个客户端,因此由用户在应用层自己实现心跳包,代码较多 且稍显复杂,而利用TCP/IP协议层为内置的KeepAlive功能来实现心跳功能则简单得多。
不论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。 因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不开启KeepAlive功 能,尽管这微不足道,但在按流量计费的环境下增加了费用。另一方面,KeepAlive设置不合理时可能会 因为短暂的网络波动而断开健康的TCP连接。并且,默认的KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多服务端应用程序来说,2小时的空闲时间太长。因此,我们需要手工开启KeepAlive功能并设置合理的KeepAlive参数。
优点:
缺点:
理解WebSocket心跳及重连机制(五)
js socket心跳链接及断线重连处理
websocket心跳及重连机制
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次握手的,而释放则需要4次握手,所以说每个连接的建立都是需要资源消耗和时间消耗的。
TCP 的长连接理论上只要连接建立后,就会一直保持着。但有时有一些防火墙之类的软件会自动检查主机的网络连接状况,比如说如果发现某个连接在几分钟之内都没有数据通讯,则会关闭这个连接。有时客户端与服务器需要实时的检测连接状态,就是需要知道对方是否还在线,如果对方不在线了,需要做相应的处理,这是就需要通过发送心跳包的方法监测链路的状态。
我们模拟一下 TCP 短连接的情况,client向server发起连接请求,server接到请求,然后双方建立连接。client向server发送消息,server回应client,然后一次读写就完成了,这时候双方任何一个都可以发起close操作,不过一般都是client先发起close操作。为什么呢,一般的server不会回复完client后立即关闭连接的,当然不排除有特殊的情况。从上面的描述看,短连接一般只会在client/server间传递一次读写操作
短连接的优点是:管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段。
接下来我们再模拟一下长连接的情况,client向server发起连接,server接受client连接,双方建立连接。Client与server完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。
首先说一下TCP/IP详解上讲到的TCP保活功能,保活功能主要为服务器应用提供,服务器应用希望知道客户主机是否崩溃,从而可以代表客户使用资源。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务器端检测到这种半开放的连接。
【本文参考】
【分布式WebSocket - 1】超详细!WebSocket协议详解
websocket和http的瓜葛以及websocket协议实现
websocket深入浅出
WebSocket介绍和Socket的区别
TCP连接 保持 保活
socket保活方案 Tcp KeepAlive和应用层HeartBeat
Socket如何保证长连接