WebSocket新手入门指南

文章目录

  • 介绍 WebSocket 的原理,了解原理后,用起来更放心大胆;
  • 类似技术对比,搞清楚自己的业务场景是不是需要使用 WebSocket;
  • 使用过程中的经验分享,让你少走一些弯路;

1 WebSocket 是什么

WebSocket 是 HTML5 新增的在单个 TCP 连接上进行全双工通讯(不受限的双向通信)的协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

全双工(Full Duplex)的通讯传输允许数据在两个方向上同时传输,相当于两个单工通信方式的结合。发送和接收分别由两根不同的传输线传送,通信双方既是发送器也是接收器。

Websocket 使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Websocket 协议使用 80 端口;运行在 TLS 上则使用 443 端口。

常见问题:

Q:WebSocket 能全双工,为何普通 HTTP 请求不行?(他们建立在 TCP 协议之上的,TCP 协议本就实现了全双工通信)
A:其实是 HTTP 的“请求-应答模式”限制了 TCP 协议本支持的全双工通信。

Q:WebSocket 和 Socket 的区别
A:Socket 不是协议,是应用层与 TCP/IP 通信的中间软件抽象层,是一组接口。而 WebSocket 是应用层协议。

Q:WebSocket 长连接和 HTTP 长连接的区别
A:HTTP/1.1 默认开启了长连接(Connection:keep-alive),本质是 TCP 长连接,可在一次 TCP 连接中完成多个 HTTP 请求。
WebSocket 的长连接是真正的全双工,TCP 链路建立后,双方可以互发消息,无需再设置请求头,且双方都需要维持住这个连接。

关于 HTTP 长连接再多说几句,打开浏览器控制台 network,每个请求都会有个 Connection ID,这表示 TCP 连接的 id,会发现可能多个 HTTP 请求的 Connection ID 是一样的,这代表他们共用一个 TCP 连接。
另外 chrome 允许一个域名有 6 个 TCP 连接并发,意味着同时发出的请求超过这个数字,只能排队了

2 为什么要用 WebSocket

2.1 需求描述、应用场景

  • 需求:服务端数据更新,需要通知到客户端。
  • 应用场景:聊天软件、订阅、游戏、协同工作(比如文本编辑)、直播、股票基金、基于位置的应用等。

2.2 常用解决方案对比

WebSocket 能解决上述需求,除此之外,常用的解决方案还有:轮询、长轮询。另外 html5 还提供了 Server-Sent Event。

  • 轮询:客户端定时向服务端发送 http 请求,服务端收到请求后立即返回响应信息并关闭连接;
  • 长轮询:为了解决轮询无效请求过多的问题,长轮询进行了优化,服务端收到请求后先阻塞,必要时再返回数据并关闭连接,客户端处理完响应信息后才再向服务端发送新的请求;
  • Server-Sent Event:html5 提供的,借用了长轮询的思想,但不再每个连接只收发一个消息,将文本数据换成流以实现重复在一个连接上收发消息;
常用方案 通讯方式 触发方式 缺点 优点
轮询 http 轮询 服务端不能主动推送;消息不及时;浪费带宽 实现容易
长轮询 http 轮询 服务端仍不能主动推送;占用 web 连接 实现较容易
Server-Sent Event http 事件 兼容性问题(不支持 ie); 占用 web 连接;只能服务端向客户端推 实现较容易;自动重连
WebSocket tcp 长连接 事件 开发成本高 全双工;安全性高;节约带宽和资源
  • Server-Sent Event 一个用于微信支付的案例:https://www.jianshu.com/p/9a0e802b2297
SSE suffers from a limitation to the maximum number of open connections, which can be specially painful when opening various tabs as the limit is per browser and set to a very low number (6). The issue has been marked as "Won't fix" in Chrome and Firefox
  • 长轮询和 SSE 会占用浏览器有限的连接数(chrome 有 6 个),看起来很致命啊

另外 HTTP/2 提供了服务器推送(Server Push)的功能,千万别和上面几个东西搞混了,完全不是一回事。服务器指的是 web 服务器,推送的对象是浏览器要加载的资源,是用于提升首屏加载速度的技术,需要在 web 服务器(比如 nginx)中开启相关配置。可以参考这篇:https://www.cnblogs.com/wetest/p/8040202.html

3 WebSocket 连接建立过程

WebSocket并不是全新的协议,而是利用了HTTP协议来建立连接。我们来看看WebSocket连接是如何创建的。

3.1 浏览器发起一个 http 请求建立连接

请求地址以ws://开头,请求头Upgrade: websocketConnection: Upgrade表示这个连接将要被转换为 WebSocket 连接。

  • 1.1 建立 TCP 连接
  • 1.2 浏览器发送 HTTP 请求,并携带协议升级的头信息,进行协议升级前的握手

3.2 服务器响应请求

响应头HTTP/1.1 101 Switching ProtocolsUpgrade: websocket表示本次连接的 HTTP 协议即将被更改(代码 101),改为指定的 WebSocket 协议。

  • 2.1 响应 HTTP 握手,返回 code 101
  • 2.2 双方可以通过这个连接自由的传信息,连接会持续存在,server 和 client 都可单方面断开连接

4 使用需知 & 实用指南

4.1 正确使用 ws 和 wss

  • WebSocket 的协议标识符是ws,如果在 TLS 协议上,标识符是wss,类似于 https
  • https 下必须使用 wss 作为安全链接

TLS 之上的 Websocket:首先,浏览器用 wss://xxx 创建 WebSocket 连接时,会先通过 HTTPS 创建安全的连接,然后,该 HTTPS 连接升级为 WebSocket 连接,底层通信走的仍然是安全的 SSL/TLS 协议。

4.2 使用 Nginx 代理 WebSocket 请求

  • Nginx 从 1.3 开始就支持 WebSocket 了,并且可以为 WebSocket 应用程序做反向代理和负载均衡。官方文档:http://nginx.org/en/docs/http/websocket.html
  • 当客户端发过来一个协议升级的 http 请求时,Nginx 默认是不知道的,需要配置proxy_set_header Upgrade $http_upgradeproxy_set_header Connection "Upgrade", 配置后,当 Nginx 代理服务器拦截到客户端发来的 Upgrade 请求时,会使用 101(交换协议)返回响应,在客户端和代理服务器、后端服务器之间建立隧道来支持 WebSocket。
  • 配置示例:
server {
    listen       80;
    server_name dev-staff-api-gateway.teyixing.com;
    rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
    server_name dev-staff-api-gateway.teyixing.com;
    listen 443 http2 ssl;

    ssl_certificate conf.d/cert/teyixing.com.pem;
    ssl_certificate_key conf.d/cert/teyixing.com.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

    # 用于 WebSocket
    location /v1/webSocket {
        proxy_pass http://dev-staff-api-gateway/v1/webSocket; # http://call-center/v1/webSocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }

    # 拦截普通 http 请求
    location / {
        proxy_pass http://dev-staff-api-gateway;
    }
}

4.3 如何解决 nginx 掐断 WebSocket 连接的问题

4.3.1 问题简述

有时候会发现 WebSocket 连接莫名其妙断了,后端日志发现有如下报错:

com.tehang.callcenter.application.websocket.WebSocketConnection.onError
java.io.EOFException: null
 at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1208)
 at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1142)
 at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:72)
 at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171)
 at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151)
 at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148)
 at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
 at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53)
 at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
 at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
 at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
 at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
 at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 at java.base/java.lang.Thread.run(Thread.java:834)
4.3.2 原因
  • nginx 配置项 proxy_read_timeout 的默认值为 60s,表示等待服务器响应的时间。也就是说,当 WebSocket 使用 nginx 转发时,如 60s 内没有通讯,nginx 便会掐断连接。
4.3.3 解决方案
  • nginx proxy_read_timeout 设置为不超时
  • 前端发起心跳检测
  • 前端在 WebSocket 生命周期方法 onError 中调用 reconnect

进阶教程

[WebSocket入门]手把手搭建WebSocket多人在线聊天室(SpringBoot+WebSocket)

https://blog.csdn.net/qqxx6661/article/details/98883166

[WebSocket]第二章:WebSocket集群分布式改造——实现多人在线聊天室

https://blog.csdn.net/qqxx6661/article/details/100064741

[WebSocket]使用WebSocket实现实时多人答题对战游戏

https://blog.csdn.net/qqxx6661/article/details/100597812

你可能感兴趣的:(【后端开发实战经验】,websocket,网络,网络协议)