利用去语言编写一个简单的WebSocket推送服务

  

本文中代码可以在github.com/alfred-zhong/wserver获取。

  


  

  

最近拿到需求要在网页上展示报警信息。以往报警信息都是通过短信,微信和应用推送给用户的,现在要让登录用户在网页端也能实时接收到报警推送。

  

依稀记得以前工作的时候遇到过类似的需求。因为以前的浏览器标准比较陈旧,并且那时用Java较多,所以那时候解决这个问题就用了Comet4J。具体的原理就是长轮询,长链接。但现在毕竟html5流行开来了,即都被边缘接替了,再用以前这种技术就显得过时。

  

很早以前就听过WebSocket的大名,但因为那时很多用户的浏览器还不支持,所以对这个技术也就是浅尝辄止,没有太深入研究过。现在趁着项目需要,就来稍微深入了解一下。

  

  

以往浏览器要获取服务端数据,都是通过发送HTTP请求,然后等待服务端回应的。也就是说浏览器端一直是整个请求的发起者,只有它主动,才能获取到数据。而要让浏览器一侧能够获取到服务端的实时数据,就需要不停地向服务端发起请求。虽然大多数情况下并没有获取到实际数据,但这大大增加了网络压力,对于服务端来说压力也直线上升。

  

利用去语言编写一个简单的WebSocket推送服务

  

后来我们学会了使用长连接+长轮询的方式。换句话说,也就是延长HTTP请求的存在时间,尽量保持HTTP连接,虽然这在一定程度上降低了不少压力,但仍然需要不停地进行轮询,也做不到真正的实时性。(借用一张图)

  

利用去语言编写一个简单的WebSocket推送服务

  

随着HTML5的到来,WebSocket在2011年被定为标准(详情请参见RFC 6455)。

  

借用《去网络编程》的话.WebSocket采用了一些特殊的报头,使得浏览器和服务器只需要做一个握手的动作,就可以在浏览器和服务器之间建立一条连接通道。且此连接会保持在活动状态,你可以使用JavaScript来向连接写入或从中接收数据,就像在使用一个常规的TCP套接字一样。它解决了Web实时化的问题。

  

利用去语言编写一个简单的WebSocket推送服务

  

由于WebSocket是全双工通信,所以当建立了WebSocket连接之后,接下来的通信就类似于传统的TCP通信了。客户端和服务端可以相互发送数据,不再有实时性的问题。

  

  

在去官方的SDK中,并不包含对WebSocket的支持,所以必须使用第三方库。

  

要使用Golang开发WebSocket,选择基本就在x/net/websocket和大猩猩/WebSocket之间,《网络编程》一书中的例子使用了x/net/websocket作为开发包,而且貌似它也更加官方且正式。而实际根据我在网上查询得到的反馈看来,并非如此。x/net/websocket貌似错误较多,且较为不稳定,问题解决也并不及时。相比之下,大猩猩/WebSocket则更加优秀。

  

还有对于大猩猩web toolkit组织的贡献,必须予以感谢# 128591;公司。其下不仅有WebSocket的实现,也有一些其他工具。欢迎大家使用并且能够给予反馈或贡献。

  

利用去语言编写一个简单的WebSocket推送服务

  

推送服务实现
  基本原理
  

  

项目初步设计如下:

  

利用去语言编写一个简单的WebSocket推送服务

  

服务器启动以后会注册两个处理器。

  

websocketHandler用于提供浏览器端发送升级请求并升级为WebSocket连接。
  pushHandler用于提供外部推送端发送推送数据的请求。
  

  

浏览器首先连接websocketHandler(默认地址为ws://ip:港口/ws)升级请求为WebSocket连接,当连接建立之后需要发送注册信息进行注册。这里注册信息中包含一个令牌信息.server会对提供的令牌进行验证并获取到相应的userId(通常来说,一个userId可能同时关联许多令牌),并保存维护好牌,userId和康涅狄格州(连接)之间的关系。

  

推送端发送推送数据的请求到pushHandler(默认地址为ws://ip:港口/推),请求中包含了userId字段和消息字段.server会根据userId获取到所有此时连接到该服务器的康涅狄格州,然后将消息一一进行推送。

利用去语言编写一个简单的WebSocket推送服务