socketio 服务器推送

如果面试官问你:要把服务器端的数据时时显示在浏览器上怎么实现?我想有很多人会回答使用Ajax技术定时去访问一个资源,没错,使用Ajax的确能实现,但面试官要的绝对不是这个答案。因为使用Ajax频繁访问给服务端造成太大的压力,所以在大部分情况下都是不取的。面试官想要的答案应该是将服务器端的数据推送至浏览器,这样只需要保持一个长链接就可以了。

socket.io就能实现数据的时时推送,socket.io(官网:http://socket.io/)是一个跨平台,多种连接方式自动切换时时引擎。要说明的是,socket.io.js只能完成客户端功能,还需要服务器端的实现才能真正完成数据的推送。socket.io官方给出的例子服务端使用Node.js实现,我想还有很多人对node.js是陌生的(me too)。socket.io服务端实现可以有多种语言,应该说只要能支持socket协议就可以。

下面的例子将给出两个Java语言的服务端实现及其使用示例。示例内容很简单,就是在服务端随机产生一个坐标(包含x,y值),然后将其推送至浏览器并显示。我想会推送一个坐标值,推送其它数据应该也不是问题。


第一种实现、netty-socketio,坐标为:com.corundumstudio.socketio:netty-socketio:1.7.3(gradle),如果使用的是maven,则坐标为:


[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <groupId>com.corundumstudio.socketio</groupId>  
  2. <artifactId>netty-socketio</artifactId>  
  3. <version>1.7.3</version>  

a.服务端代码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class Server {  
  2.     private static List<SocketIOClient> clients = new ArrayList<SocketIOClient>();//用于保存所有客户端  
  3.   
  4.     public static void main(String[] args) throws Exception {  
  5.         Configuration configuration = new Configuration();  
  6.         configuration.setHostname("127.0.0.1");//设置主机名  
  7.         configuration.setPort(8082);//设置监听的端口号  
  8.         SocketIOServer server = new SocketIOServer(configuration);//根据配置创建服务器对象  
  9.   
  10.         server.addConnectListener(new ConnectListener() {//添加客户端连接监听器  
  11.             @Override  
  12.             public void onConnect(SocketIOClient client) {  
  13.                 System.out.println("connected:SessionId=" + client.getSessionId());   
  14.                 clients.add(client);//保存客户端  
  15.             }  
  16.         });  
  17.           
  18.         server.start();  
  19.         System.out.println("server started");  
  20.         Timer timer = new Timer();  
  21.         timer.schedule(new TimerTask() {  
  22.             @Override  
  23.             public void run() {  
  24.                 Random random = new Random();  
  25.                 for(SocketIOClient client : clients) {  
  26.                     client.sendEvent("pushpoint"new Point(random.nextInt(100), random.nextInt(100)));//每隔一秒推送一次  
  27.                 }  
  28.             }  
  29.         }, 10001000);  
  30.           
  31.         Object object = new Object();  
  32.         synchronized (object) {  
  33.             object.wait();  
  34.         }  
  35.     }  
  36.   
  37. }  

b.Point类:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class Point {  
  2.     private int x;  
  3.     private int y;  
  4.       
  5.     public Point(int x, int y) {  
  6.         this.x = x;  
  7.         this.y = y;  
  8.     }  
  9.       
  10.     //getter,setter  
  11. }  

c.html页面:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title>netty-socketio测试</title>  
  5.     <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>  
  6.     <script src="socket.io/socket.io-1.0.6.js"></script>  
  7.     <script src="jquery-1.7.2.min.js"></script>  
  8.     <script>  
  9.         $(function(){  
  10.             var socket =  io.connect('http://127.0.0.1:8082');  
  11.             //监听名为pushpoint的事件,这与服务端推送的那个事件名称必须一致  
  12.             socket.on("pushpoint", function(data){  
  13.                 $('#x').text(data.x);  
  14.                 $('#y').text(data.y);  
  15.             });  
  16.         });  
  17.           
  18.     </script>  
  19. </head>  
  20.   
  21. <body>  
  22.       
  23.     <div id="display" style="height:50px;background-color:grey;">  
  24.         x=<span id="x">0</span>y=<span id="y">0</span>  
  25.     </div>  
  26.   
  27. </body>  
  28.   
  29. </html>  

第二种实现、socketio-netty(上面一个是netty-socketio),这个实现在maven中央库中好像还没有,该项目托管在google code上,项目地址为:http://code.google.com/p/socketio-netty/,本人是把它下载下来后手动安装在私服上的,现已上传至:http://download.csdn.net/detail/xtayfjpk/9720229,可供下载。
a.服务端代码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class Server2 {  
  2.     private static List<IOClient> clients = new ArrayList<IOClient>();  
  3.   
  4.     public static void main(String[] args) throws Exception {  
  5.         SocketIOServer ioServer = new SocketIOServer(new IOHandlerAbs() {  
  6.               
  7.             @Override  
  8.             public void OnShutdown() {  
  9.                 System.out.println("shut down");                  
  10.             }  
  11.               
  12.             @Override  
  13.             public void OnMessage(IOClient client, String eventName) {  
  14.                 System.out.println("receive message,eventName=" + eventName);  
  15.             }  
  16.               
  17.             @Override  
  18.             public void OnDisconnect(IOClient client) {  
  19.                 System.out.println("disconnect");                 
  20.                 System.out.println("disconnect");                 
  21.             }  
  22.               
  23.             @Override  
  24.             public void OnConnect(IOClient client) {  
  25.                 System.out.println("connect");  
  26.                 clients.add(client);  
  27.             }  
  28.         }, 8088);  
  29.           
  30.         ioServer.start();  
  31.         System.out.println("server started");  
  32.         Timer timer = new Timer();  
  33.         timer.schedule(new TimerTask() {  
  34.             @Override  
  35.             public void run() {  
  36.                 Random random = new Random();  
  37.                 String data = "{\"x\":" +random.nextInt(100)+ ",\"y\":" +random.nextInt(100)+ "}";  
  38.                 BASE64Encoder encoder = new BASE64Encoder();  
  39.                 data = encoder.encode(data.getBytes());  
  40.                 for(IOClient client : clients) {  
  41.                     client.send(formatMessage(data));  
  42.                 }  
  43.             }  
  44.         }, 10001000);  
  45.           
  46.         Object object = new Object();  
  47.         synchronized (object) {  
  48.             object.wait();  
  49.         }  
  50.     }  
  51.   
  52.     private static String formatMessage(String data) {  
  53.         return String.format(  
  54.                 "5:::{\"%s\":\"%s\",\"%s\":[\"%s\"]}",//socket.io字符串格式  
  55.                 "name",  
  56.                 "push",//事件名称  
  57.                 "args",  
  58.                 data//携带的数据  
  59.                 );  
  60.     }  
  61. }  

需要说明的是,该实现不能像上一个实现一样发送一个对象,只能发送一个字符串,而且该字符串中还不能包含双引号(也许还有其它特殊字符)。而推送过程中我们使用的数据格式很可能是JSON,那就肯定有双引号,所以这里采取的办法是对要发送的数据进行BASE64编码,然后在客户端解码回来得到我们想要的数据。

b.html页面:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title>socketio-netty测试</title>  
  5.     <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>  
  6.     <script src="socket.io/socket.io-0.9.6.js"></script>  
  7.     <script src="crypto-js/core-min.js"></script>  
  8.     <script src="crypto-js/enc-base64-min.js"></script>  
  9.     <script src="crypto-js/enc-utf16-min.js"></script>  
  10.     <script src="jquery-1.7.2.min.js"></script>  
  11.     <script>  
  12.         $(function(){  
  13.             var host = "http://127.0.0.1:8088";  
  14.             var socket = null;  
  15.             if(/MSIE (\d+.\d+);/.test(navigator.userAgent)){  
  16.                 if(/MSIE 10(.\d+);/.test(navigator.userAgent)){  
  17.                     socket = io.connect(host);  
  18.                 }else{  
  19.                     socket = io.connect(host,{transports:['jsonp-polling']});   
  20.                 }  
  21.             } else {  
  22.                 socket = io.connect(host,{transports:['websocket','flashsocket','htmlfile','xhr-polling','jsonp-polling']});   
  23.             }  
  24.   
  25.             socket.on("push", function(data){  
  26.                 var words  = CryptoJS.enc.Base64.parse(data);  
  27.                 var point  = CryptoJS.enc.Utf8.stringify(words);  
  28.                 point = JSON.parse(point);  
  29.                 $('#x').text(point.x);  
  30.                 $('#y').text(point.y);  
  31.             });  
  32.         });  
  33.           
  34.     </script>  
  35. </head>  
  36.   
  37. <body>  
  38.       
  39.     <div id="display" style="height:50px;background-color:grey;">  
  40.         x=<span id="x">0</span>y=<span id="y">0</span>  
  41.     </div>  
  42.   
  43. </body>  
  44.   
  45. </html>  

第一个例子中实现的socket.io版本为1.0.6,第二个使用的版本为0.9.6。这两种服务端实现都是基于netty框架的,但个人觉得还是第一种实现比较好用,省去了编码的过程,而且封装程度更高。

示例代码工程已托管在GitHub中,使用gradle进行构建,地址为:https://github.com/xtayfjpk/socketio-test

只要将其捡出即可运行。


原文地址:http://blog.csdn.net/xtayfjpk/article/details/40948409

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值