前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SocketIO:服务端推送就是这么简单!

SocketIO:服务端推送就是这么简单!

作者头像
Bug开发工程师
发布2019-05-04 22:03:16
6.3K0
发布2019-05-04 22:03:16
举报
文章被收录于专栏:码农沉思录

前言

在介绍SocketIO之前,先说下服务端推送是怎么一回事。所谓服务端推送,就是服务端将数据或者消息实时地推送到客户端上。最常见的场景就是即时通讯,除此之外,视频弹幕、图文直播等功能也用到了服务端推送这项技术。

之所以使用服务端推送,是为了把服务端的数据及时、迅速地推送到客户端,当然,如果能够尽可能地降低服务端的性能损耗,那就再好不过了。

要想及时地获取服务端数据,最简单的实现方案莫过于客户端长轮询了。简而言之,就是客户端起一个定时器,定时向服务端发送HTTP请求查询最新数据,以此实现客户端与服务端的数据保持一致。这种方案的好处是实现简单,坏处就是性能损耗过高,而且数据更新也不及时。由于需要定时向服务器发送HTTP请求,如果客户端数量过多,则服务器需要承受很大的并发压力。再者,服务端的数据更新可能并不频繁,但是客户端也要定期过来询问,这会让服务端和客户端都做很多无用功,效率自然不高。还有一点就是,由于客户端没法做到每时每刻都向服务端请求数据,只能定时请求,假如说相邻2次请求的间隔时间过长,则服务端的数据就没法及时地“推送”到客户端,这会造成数据推送延迟。

服务端推送的其他方案

客户端长轮询方案是最简单的方案,但是缺点诸多,业界应该没几家公司会采用。我们都知道,TCP协议是支持双向通信的,也就是说服务端可以向客户端发送数据包,客户端也可以向服务端发送数据包。但由于HTTP协议的限制,基于HTTP协议通信的网络应用只能由客户端主动发起,服务端被动响应,故无法做到服务端向客户端推送数据。虽然HTTP 2.0支持服务端推送,但是HTTP 2.0的服务端推送跟我们这里说的服务端推送还不是一回事,有兴趣的朋友可以去深入了解下。

既然TCP协议支持服务端推送,而HTTP协议不支持,那么事情就好办了。我们传输层依旧使用TCP协议,应用层改用其他协议不就得了。事实上,业界也确实是这么做的。最常见的方案就是使用现成的协议,如WebSocket。当然,也可以使用自定义协议来实现服务端推送。关于WebSocket协议这里不会展开细讲,感兴趣的可以看旧文:一文读懂WebSocket

如果直接使用WebSocket协议作为服务端与客户端通信协议的话,则意味着服务端与客户端还要关注心跳检测、自动重连等细节,如果使用自定义协议,则还要进行协议的解析,以及拆包粘包等工作,未免过于繁杂。因此,SocketIO应运而生。

SocketIO是什么

SocketIO是一套支持实时双向事件驱动的服务端与客户端通信的解决方案,或者说规范。其基于WebSocket协议,天生支持服务端推送。此外,其还封装了连接检测、自动重连等细节,并且支持命名空间与群聊。不仅如此,它还支持基于反向代理来搭建服务器集群。

因此,使用SocketIO可以很方便地搭建支持服务端推送的集群,而且还无需关注底层连接建立、连接检测等细节。

不过需要指出的是,SocketIO不仅仅支持WebSocket协议,也支持HTTP长轮询的方式来实现服务端推送。这取决于客户端支不支持WebSocket协议,如果客户端支持WebSocket协议,则服务端会优先采用WebSocket协议与客户端通信,假如说客户端不支持WebSocket,则服务端会降级成使用HTTP长轮询的方式来通信。不过,这一切对于使用者来说都是透明的。而且,服务端也可以强制指定使用WebSocket协议来通信。

还有一点,SocketIO使用的不是标准的WebSocket协议,其在每个数据包里增加了一些元数据,如:命名空间、ack id等。因此如果服务端是一个SocketIO服务器,而客户端使用标准的WebSocket协议与服务端通信的话,是没法建立连接的。幸好,SocketIO服务端跟客户端都有相应的开源库,社区也很活跃,所以使用起来非常方便。

SocketIO使用

接下来来看下SocketIO如何使用。

本文使用的服务端是Java语言的实现netty-socketio,项目地址:https://github.com/mrniko/netty-socketio。客户端也是Java语言的开源库socket.io-client-java,项目地址:https://github.com/socketio/socket.io-client-java。

先来看下服务端demo。

首先新建maven工程,引入netty-socketio依赖:

代码语言:javascript
复制
<dependency><groupId>com.corundumstudio.socketio</groupId><artifactId>netty-socketio</artifactId><version>1.7.17</version></dependency>

然后,开始编写SocketIO服务端代码:

代码语言:javascript
复制
import com.corundumstudio.socketio.Configuration;import com.corundumstudio.socketio.SocketConfig;import com.corundumstudio.socketio.SocketIOClient;import com.corundumstudio.socketio.SocketIOServer;import com.corundumstudio.socketio.listener.ConnectListener;
public class Server {
public static void main(String[] args){    Configuration config = new Configuration();    config.setPort(1337);final SocketConfig socketConfig = new SocketConfig();    socketConfig.setReuseAddress(true);    config.setSocketConfig(socketConfig);    SocketIOServer server = new SocketIOServer(config);    server.addConnectListener(new ConnectListener() {@Overridepublic void onConnect(SocketIOClient socketIOClient) {        System.out.println(socketIOClient.getSessionId()+" has connected.");      }    });    server.start();  }}

代码很简单,就是设置监听端口,以及设置一些tcp参数,然后添加连接事件监听器,这里的连接监听器逻辑比较简单,就是把客户端的sessionId打印出来而已。最后再启动SocketIO服务器。

SocketIO除了能监听连接事件外,还能监听连接断开事件,以及自定义事件。这里为了方便,只使用了连接监听器。

接下来再编写SocketIO客户端demo。

首先,引入maven依赖socket.io-client-java。

代码语言:javascript
复制
<dependency><groupId>io.socket</groupId><artifactId>socket.io-client</artifactId><version>1.0.0</version></dependency>

接着编写客户端代码。

代码语言:javascript
复制
import io.socket.client.IO;import io.socket.client.Socket;import io.socket.emitter.Emitter;
public class Client {
public static void main(String[] args) throws Exception{final Socket socket = IO.socket("http://localhost:1337");    socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Overridepublic void call(Object... args) {        System.out.println("I have connected to server.");      }
    });    socket.connect();  }}

客户端的代码也很简单。首先设置服务端的ip地址和端口,然后设置连接监听器,这里也只是简单地打印一句话而已。最后开启连接。同样地,客户端除了可以监听连接事件,也可以监听断连事件,以及自定义事件。

最后,先后启动服务端与客户端,可以看到服务端的控制台输出如下:

代码语言:javascript
复制
afbecfc5-032d-4e04-a937-faa521b0c7a2 has connected.

客户端的控制台输出如下:

代码语言:javascript
复制
I have connected to server.

至此,一个简易的SocketIO通信demo业已完成。

连接一旦建立,服务端与客户端就可以进行双向通信了。

扩展

不知到了这里,大家是否有这样的疑问:前面不是说SocketIO使用的是WebSocket协议通信吗?那么客户端建立连接的时候,设置的连接串为什么使用的是HTTP协议呢?其实大家可以试着把客户端代码的HTTP协议改为WebSocket协议试试:ws://localhost:1337。然后再先后运行服务端与客户端,会发现客户端报如下错误:

代码语言:javascript
复制
Exception in thread "main" java.lang.RuntimeException: java.net.MalformedURLException: unknown protocol: wsat io.socket.client.Url.parse(Url.java:52)at io.socket.client.IO.socket(IO.java:61)at io.socket.client.IO.socket(IO.java:42)at io.socket.client.IO.socket(IO.java:38)at socketio.Client.main(Client.java:10)Caused by: java.net.MalformedURLException: unknown protocol: wsat java.net.URL.<init>(URL.java:600)at java.net.URL.<init>(URL.java:490)at java.net.URL.<init>(URL.java:439)at io.socket.client.Url.parse(Url.java:46)  ... 4 more

报的是未知协议异常。

所以客户端建立连接的时候只能先使用HTTP协议,再升级到WebSocket协议进行通信。至于WebSocket协议的升级细节,可以看旧文:一文读懂WebSocket。这里不再赘述。

以后有时间再讲讲SocketIO的集群方案,以及踩过的坑。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农沉思录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档