50字范文,内容丰富有趣,生活中的好帮手!
50字范文 > 服务端推送技术方案-让你的消息更及时

服务端推送技术方案-让你的消息更及时

时间:2022-05-06 07:35:28

相关推荐

服务端推送技术方案-让你的消息更及时

背景:在上一篇文章中介绍了扫码登录的原理,其中涉及到了服务端和客户端的通信,客户端如何能获取最新的状态?服务端又怎样把最新的消息推送给客户端?本文将围绕服务端和客户端的通信展开叙述。

以HTTP为基础的请求中,服务端“推送”方案有三种,这里其实的推送并不是严格意义上的推送,这里是以获取服务端最新及时的消息为重点,只有第三种方案是服务端推送。

1 基于轮询

2 长训轮(long-polling)

3 长链接

接下来分别讲述下这三种方案的优缺点和使用场景。

1 基于轮询

优点:开发简单,客户端实现即可,不需要服务端配合。

缺点:大多数情况下是无用的请求,占用服务端资源。

实现方式:客户端每隔一段时间调用接口,无论有没有数据,接口立即返回.

使用场景:不想折腾的开发者,消息及时性要求没那么高,服务器资源资源足。

$(function() {get();setInterval("getMsg();",5000);});function getMsg(){$.ajax({url : "${APP_PATH}/getMsg",data : {},datatype: "json",type : "post",success : function(result) {//console.log(result);},error:function (){ } });

2 基于长轮询(long-polling)

优点:消息及时,命中率高,消耗服务端资源少

缺点:服务端和客户端需要同时改造,消息会有部分延迟(发生在请求交替之时)

实现方式:客户端在上次请求返回后,在发送下次请求,服务端当有数据或者超时后返回,没有数据时hang住链接(超时时间需要综合考虑服务器性能和及时性做出平衡,有代理的话需要考虑代理对于链接的超时机制)。

使用场景:扫码登录,微信网页端获取消息等。

客户端代码:

function getMsg(){$.ajax({url : "${APP_PATH}/getMsg",data : {},datatype: "json",type : "post",success : function(result) {//处理逻辑getMsg();},error:function (){ getMsg();} });

服务端代码:

@RequestMapping("/getMsg")public void getMsg(long timed, HttpServletResponse response) throws Exception {PrintWriter writer = response.getWriter();//模拟redis有消息long start= System.currentTimeMillis();while (true) {String msg=redisGetMsg(key);if(StringUtils.isNotBlank(msg){writer.write(msg);break;}else{if(System.currentTimeMillis()-start)>20000){ //约定hold住20s,会有部分偏差writer.write(“”);break;}} }}

2 长链接

优点:通信及时,通信模式采用双工,类似于打电话

缺点:服务端和客户端需要同时改造,当链接过多时,消耗服务端资源比较大。

实现方式:客户端和服务端建立长链接,基于http1.1 ,keepalive ,websocket,comet,iframe等,基于socket的需要维持心跳

使用场景:实时性要求很高,银行系统,股票系统等

基于websocket案例代码前端:

<script type="text/javascript">function WebSocketTest(){if ("WebSocket" in window){alert("您的浏览器支持 WebSocket!");// 打开一个 web socketvar ws = new WebSocket("ws://localhost:9998/echo");ws.onopen = function(){// Web Socket 已连接上,使用 send() 方法发送数据ws.send("发送数据");alert("数据发送中...");};ws.onmessage = function (evt) { var received_msg = evt.data;alert("数据已接收...");};ws.onclose = function(){ // 关闭 websocketalert("连接已关闭..."); };}else{// 浏览器不支持 WebSocketalert("您的浏览器不支持 WebSocket!");}}</script>

后端websocket代码:

备注:链接需要维护连接池,对于java有两种方式:1 使用tomcat容器支持实现 2 spring 4.x实现websocket,前端需要socketjs

ublic class WsServer extends WebSocketServer {public WsServer(int port) {super(new InetSocketAddress(port));}public WsServer(InetSocketAddress address) {super(address);}@Overridepublic void onOpen(WebSocket conn, ClientHandshake handshake) {// ws连接的时候触发的代码,onOpen中我们不做任何操作}@Overridepublic void onClose(WebSocket conn, int code, String reason, boolean remote) {//断开连接时候触发代码userLeave(conn);System.out.println(reason);}@Overridepublic void onMessage(WebSocket conn, String message) {System.out.println(message);if(null != message &&message.startsWith("online")){String userName=message.replaceFirst("online", message);//用户名userJoin(conn,userName);//用户加入}else if(null != message && message.startsWith("offline")){userLeave(conn);}}@Overridepublic void onError(WebSocket conn, Exception ex) {//错误时候触发的代码System.out.println("on error");ex.printStackTrace();}/*** 去除掉失效的websocket链接* @param conn*/private void userLeave(WebSocket conn){WsPool.removeUser(conn);}/*** 将websocket加入用户池* @param conn* @param userName*/private void userJoin(WebSocket conn,String userName){WsPool.addUser(userName, conn);}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。