谈谈http/tcp的长连接和websocket的长连接
Posted 诺浅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了谈谈http/tcp的长连接和websocket的长连接相关的知识,希望对你有一定的参考价值。
HTTP 协议的“缺陷”
了解http的人都知道,HTTP 协议有一个缺陷:通信只能由客户端发起。例如,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息的, 这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦,客户端只能使用"轮询"的方式,即每隔一段时间,就发出一个请求,请求服务器有没有状态变化 。可见轮询的效率低,非常浪费资源。
在http1.1中,默认开启了一个叫Keep-alive的参数,官方的说法是可以用这个来作为长连接。你是否以为既然客户端与服务器保持了长连接,服务器就能主动给客户端推送消息呢?
关于Keep-alive的缺点
Keep-alive
的确可以实现长连接,但是这个长连接是有问题的,本质上依然是客户端主动发起-服务端应答的模式,是没法做到服务端主动发送通知给客户端的。也就是说,在一个HTTP连接中,客户端可以发送多个Request
,接收多个Response
。但是请记住 Request = Response
,在HTTP中永远是这样,一个Request
只能有一个Response
。而且这个Response
也是被动的,不能主动由服务端发起。
放上一张图,图左为没开启Keep-alive
,图右为开启了Keep-alive
,可以看出即使开启了Keep-alive
,交互模式依然是一问一答的模式,相较没开启Keep-alive
只是省略了每次连接的关闭和打开操作。我理解是由于tcp交互之前是需要三次握手的,而开启了Keep-alive
只是节省了握手这个过程(不对请指出)。
关于http2.0多路复用
需要注意的是Keep-alive
是指不需要多次建立连接,而非http2.0
里面的多路复用,多路复用的意思是客户端可以同时向服务器端发送多个请求,服务器端也可以同时响应多个Response.
上面讲述了http协议的缺点,那么如果我们需要服务器状态变化的时候能够主动通知客户端,我们有没有什么办法呢?
这种需求很常见,比如微信扫描PC页面上的二维码登录,在扫描完了之后页面就会跳转,那么页面是处于客户端PC上,他是如何知道我们通过手机扫描了这个二维码的呢?这其实就是一个服务端通知客户端的很典型的例子,微信后台接收到手机微信扫描完成的
消息进而通知客户端PC页面进行跳转。这就可以用到websocket
,当然只是说websocket
可以实现这个功能,并不是说是唯一的解决方案,也不是说微信是使用这个技术来实现的,不要杠~
关于websocket
websocket
的协议是在TCP/IP
协议簇的应用层,和http
在同一层,也是应用层的协议,但是它是一种双向通信协议。
上图对比可以看出,相对于传统 HTTP每次请求-应答
都需要客户端与服务端建立连接的模式,WebSocket
是类似Socket
的TCP
长连接的通讯模式,一旦 WebSocket
连接建立后,后续数据都以帧序列的形式传输。在连接断开前,不需要重新发起连接请求。
在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。
Websocket
的流程大概是以下几步
- 客户端-服务端建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。
- TCP连接成功后,客户端通过HTTP协议向服务器传送
WebSocket
支持的版本号等信息。这一步称为开始前的HTTP握手 - 服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据,此时回馈的数据中会指明服务器的
WebSocket
支持的版本号等信息 - 当客户端收到了连接成功的消息后,通过TCP通道进行传输通信。
也就是说WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。
一次websocket的握手请求与应答的报文
WebSocket 客户端请求报文
GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin:
http://localhost
:8080
Sec-WebSocket-Version: 13
可以看到,客户端发起的 WebSocket
连接报文类似传统 HTTP
报文,
Upgrade:websocket
参数值表明这是 WebSocket
类型请求
Sec-WebSocket-Key
是 WebSocket
客户端发送的一个 base64
编码的密文,要求服务端必须返回一个对应加密的Sec-WebSocket-Accept
应答,否则客户端会抛出Error during WebSocket handshake
错误,并关闭连接。
服务端收到报文后返回的数据格式类似:
WebSocket 服务端响应报文
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
Sec-WebSocket-Accept
的值是服务端采用与客户端一致的密钥计算出来后返回客户端的,HTTP/1.1 101 Switching Protocols
表示服务端接受 WebSocket
协议的客户端连接,经过这样的请求-响应处理后,客户端服务端的 WebSocket
连接握手成功, 后续就可以进行 TCP
通讯了。
WebSocket与Socket的关系
Socket
其实并不是一个协议,而是为了方便使用TCP
或UDP
而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。在设计模式中,Socket
其实就是一个门面模式
,它把复杂的TCP/IP协议族
隐藏在Socket
接口后面,对用户来说,一组简单的接口就是全部,让Socket
去组织数据,以符合指定的协议。
当两台主机通信时,必须通过Socket
连接,Socket
则利用TCP/IP
协议建立TCP/UDP
连接。TCP/UDP
连接则更依靠于底层的IP协议
,IP协议的连接则依赖于链路层等更低层次。
WebSocket
则是一个典型的应用层协议。
我觉得上诉话并没有把二者的区别说清楚,简单来说Socket只是一个使用tcp的接口而已,tcp只是协议,他需要有API才能使用他,而socket提供了这些api。
WebSocket与html5的关系
WebSocket API
是 HTML5
标准的一部分,但这并不代表 WebSocket
一定要用在 HTML5
中,或者只能在基于浏览器的应用程序中使用。
实际上,许多语言、框架和服务器都提供了 WebSocket 支持,例如:
- 基于 C 的 libwebsocket.org
- 基于 Node.js 的 Socket.io
- 基于 Python 的 ws4py
- 基于 C++ 的 WebSocket++
- Apache 对 WebSocket 的支持:Apache Module mod_proxy_wstunnel
- nginx 对 WebSockets 的支持:NGINX as a WebSockets Proxy 、 NGINX Announces Support for WebSocket Protocol 、WebSocket proxying
- lighttpd 对 WebSocket 的支持:mod_websocket
写在最后
觉得本文不错的朋友,点个赞吧,你的赞是我持续写作的动力。
参考:https://www.cnblogs.com/Javi/p/9303020.html
以上是关于谈谈http/tcp的长连接和websocket的长连接的主要内容,如果未能解决你的问题,请参考以下文章