WebSocket介绍
1.背景
WebSocket和http协议一样是应用层的协议,通过握手机制可以使客户端和服务端建立类似tcp的连接。在WebSocket出现之前客户端向服务器发出请求是通过http协议实现的,而http协议有个特点是通行请求只能由客户端发起,然后服务端响应查询结果,HTTP 协议没法让服务器主动向客户端推送信息。这样如果服务器有连续的状态变化,比如新消息,客户端要获知就非常麻烦,只能通过轮询,长轮询的方式,但是这样的效率很低,消耗了不必要的服务器资源(因为必须不停发送http连接,或者http连接保持始终打开。在 HTTP1.1 协议中的 keep-alive connection 是指在一次 TCP 连接中完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,所以这些方式服务器和客户端还要大量交换 httpheader,信息交换效率很低)。
2.WebSocket简介
WebSocket是H5通信规范,它的出现可以解决客户端和服务端实时通信而产生的技术。WebSocket协议可以使服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,全双工(full-duplex)的方式通信,属于服务器推送技术的一种。
WebSocket协议本质上是一个基于TCP的协议,是先通过HTTP/HTTPS协议发起一条特殊的HTTP请求进行握手后创建一个用于交换数据的TCP连接之后,服务端与客户端通过此TCP连接进行实时通信。这里要注意一点,当WebSocket的客户端与服务器端进行通讯以后,此时就不再需要之前进行握手请求的HTTP协议的参与。
3. WebSocket和HTTP
1)Http和WebSocket都是工作在应用层,都是基于Tcp协议。
2)Http通信只能单方面由客户端发起,而WebSocket是双向的。http链接分为短链接,长链接,短链接是每次请求都要三次握手才能发送自己的信息。
3)WebSocket中,客户端和服务器只需要完成一次握手,就能建立持久性的连接。
4.WebSocket原理
WebSocket是基于C/S架构。
WebSocket建立连接分三个部分:
- 客户端发起握手请求。
- 服务端响应请求。
- 连接建立。
WebSocket是由Http协议握手而来,当客户端与服务端通信,客户端首先向服务端发起http请求,而这个请求的特殊性在于客户端在http头部(header)里包含了一些附加头信息,其中就有一个头信息叫做upgrade字段,告诉服务端它想要生成WebSocket协议,服务端收到之后给客户端一个握手的确认,回答客户端允许它对WebSocket协议的转换,一旦完成这个协商后,客户端和服务端的底层tcp连接是没有中断的,接下来客户端可以向服务端发送基于WebSocket协议的消息,这样就完成了HTTP协议向WebSocket协议的升级,而两端则继续复用HTTP底层socket的链接完成后续的通信。WebSocket传输单元是message,由于当传递很大的数据包时候,message会被切分成多个frame帧来传输,我们编程的时候无需关注底层的frame,只需要操作message。
wss:
使用加密WebSocket连接,WebSocket连接使用Transport Layer Security (TLS),确保浏览器使用显式代理服务器时,能够发出HTTP CONNECT命令。在WebSocket客户端和WebSocket服务器间建立一个安全隧道,通过HTTP代理提供端到端的tcp通信。
图片来源:https://cs.xieyonghui.com/architecture/http-vs-websocket_65.html
5.WebSocket生命周期
1. 打开事件。
它是发生在新的连接时调用,此事件的发生在端点上建立连接时,并且在任何其他事件发生之前,此事件伴随着几部分信息:
- webSocket Session对象用于表示已经建立好的连接。
- 配置对象包含了用来配置端点的信息,一组路径参数才能用于打开阶段。
2. 消息事件
主要用于接收WebSocket对话中另一端发送的消息。连接上的消息会以三种方式抵达(1.文本消息 2.二进制消息 3. 胖消息)。
3. 错误事件
在WebSocket连接或者端点发生错误产生,可以处理WebSocket连接运行过程中任意异常。
4. 关闭事件
表示WebSocket连接端点关闭,可以由参与连接的任意断点发出。WebSocket提供了两种关闭方式:
- 服务器关闭底层TCP连接。底层TCP连接正常是由服务端关闭,在异常情况下可以由客户端发起TCP Close。
- 客户端发起TCP Close。
6.WebSocket特点
1)建立在 TCP 协议之上,服务器端的实现比较容易。
2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
3)节省通信开销,数据格式比较轻量,性能开销小,通信高效。以前的WebServer实现推送技术或者即时通讯,用的都是轮询在特定的时间间隔,比如说一秒钟由浏览器自动发起请求,将服务器的消息主动拉回来,那么在这种情况下呢,我们需要不断的向服务器发送请求。然而呢,Http request的Header是非常长的,那么里面的包含的数据可能只是一个很小的值,这样会占用很多的带宽和服务器资源。
4)可以发送文本,也可以发送二进制数据。
5)没有同源限制,客户端可以与任意服务器通信。
6)是一个持久化通信协议,可以做长连接。
7)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
如下:
ws://example.com:80/path
7)Websocket为一次HTTP握手后,后续通讯为tcp协议的通讯方式。
8)服务器和客户端可以在给定的时间范围内任意时刻相互推送信息。浏览器和服务器只需要做一个握手的动作。在建立连接之后呢,服务器可以主动传送数据给客户端,那么客户端也可以随时向服务器发出数据。此外服务器与客户端之间交换的标头信息也是非常小的。
7.WebSocket应用场景
1)心跳包。
2)网页即时通信(Web聊天室):聊天应用程序仅使用WebSocket
建立一次连接,便能在订阅户之间交换,发布和广播消息。它重复使用相同的WebSocket
连接,用于发送和接收消息以及一对一的消息传输。
3)游戏应用程序:在游戏应用程序中,你可能会注意到,服务器会持续接收数据,而不会刷新用户界面。屏幕上的用户界面会自动刷新,而且不需要建立新的连接,因此在WebSocket
游戏应用程序中非常有帮助。
8.WebSocket后端技术选型
1.nodejs:WebSocket本身主要是应用于浏览器,属于浏览器里面的一种编程,对于前端开发nodejs比较熟悉,可以使用nodejs做长链接。不过nodejs还是js,js本身特性是单线程模型,虽然可以多进程,但是推送性能有限。
2.c/c++:使用c/c++实现WebSocket,成本比较高,可能需要手动实现对WebSocket协议对封装。
3.golang:编译型语言,速度快,多线程,实现并发容易,基于协程模型并发。所以开发起来比较简单,可以让我们更加专注于业务。其次有内置标准的WebSocket标准库,无需造轮子。
9.使用go语言完成WebSocket开发
使用go语言的 gorilla/websocket 第三方开发包来开发WebSocket 服务。
下载包:go get github.com/gorilla/websocket
利用这个开发包开发WebSocket 服务很简单,下面有个demo
package main import ( "net/http" ) func wsHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("websocket connected success!")) } func main() { http.HandleFunc("/ws",wsHandler) http.ListenAndServe("0.0.0.0:7777",nil) }
然后运行,打开浏览器,运行成功