只要服务器支持WebSocket协议(Tomcat7、Jetty7之后都是支持WebSocket的),那么服务端收到请求且建立连接成功后会返回Sec-WebSocket-Accept、Sec-WebSocket-Protocol这两个header给客户端,且Http Status为101表示协议切换成功,这样客户端和服务端只要任意一方没有断开连接,就可以基于这一条通路进行通讯了。
再谈一下之前提的WebSocket相比长短轮询对于带宽资源的节省。有一个测试,假设HTTP Header是871字节,WebSocket由于数据传输是基于帧的,帧传输更加高效,对比长短轮询,2个字节即可代替871个字节的Header,测试结果为:
相同的每秒客户端轮询的次数,当次数高达10W/s的高频率次数的时候,轮询需要消耗665Mbps,而WebSocket仅仅只花费了1.526Mbps,将近435倍。
WebSocket做到了真正的实时且大量节省带宽资源,但是我理解也有自己的问题,就是开发成本比较高,这里的开发成本倒不是说自己去实现WebSocket,这个在Java语言层面上直接使用Netty-Socketio即可,API很简单,提供了对WebSocket完整的实现,真正的开发成本在于分布式环境下的数据同步问题。
举个例子,有一个在线聊天系统10W人同时在线,此时有一个用户发了一条1K的语音消息,单机保持10W的连接倒是可以(这里不是HTTP请求,因此不受连接池数影响),问题在于带宽。单机同时向10W用户推送1K语音消息,需要的带宽至少10M,这还只是纯粹推送数据出去,没有考虑到数据进来的场景,实际运行过程中需要的带宽会更多,对于企业来说这是一笔非常大的成本。
因此,大量连接的场景下都会做集群(实际就算没有大量连接,为了高可用性,也会做集群),10W并发分出5台机器,平均每台机器有2W连接,考虑集群下会出现的问题:
客户端1把数据发送到服务器1,服务器1连接的所有客户端都可以推送该条语音,但是问题在于:
服务器2~服务器5连的所有客户端如何拿到数据?简单的一种方式是使用消息队列,将数据通过消息队列发送到所有订阅的服务器上
那如果传输的是一张1M的图片,数据太大不适合使用消息队列怎么办,可以先将数据存储下来,消息队列只发送id,收到消息的服务器再根据id去取真正的数据并推送
如果依赖消息队列,那么不仅仅需要对应用进行代码开��,还需要对消息服务器做分布式集群、做压力测试,保证高可用
2W连接正常预计发送1K的消息是没问题的,但是万一用户发送了1M图片导致远超预估带宽怎么办,是业务上取舍不能发送超过XXX的数据还是技术上处理
其他太多需要考虑的问题没有列出来,总而言之,用WebSocket在大量请求、高并发的场景下,代码开发成本是非常高的。但是由于WebSocket可以做到真正的实时服务端对客户端的数据推送且对带宽资源有大量的节省,因此很多IM、音视频、弹幕等应用都会使用WebSocket。