构建实时Web的JAVA选择组合:socket.io client + socketio-netty server
2013-03-27 10:27
555 查看
前言
现在一说到实时web,可能大家不由自主的就想到了node.js,确实,在语言级别node.js实现了异步的、基于事件机制的IO特性,使用简单。在JAVA语言层面,提供了NIO作为非阻塞IO的替代品。无论node.js还是JAVA,都没有从真正意义上实现AIO(这个需要操作系统支持,依赖内置库/运行时模拟支持)。
Websocket/Flashsocket
要说到实时Web,就不能不说到Websocket,目前存在的几个草稿协议,若是要自己实现websocket协议支持,需要注意其握手协议等。目前对Websocket的支持,caniuse.com 给出了一张图表,详细说明了各个浏览器的支持情况:
粉红色区域表示不支持Websocket。
至于IE浏览器,以及部分陈旧的桌面浏览器,可以选择Flashsocket作为替代品。
客户端如何把Websocket和Flashsocket结合在一起使用,可借鉴开源项目:web-socket-js (客户端的Websocket实现方案)
其思路和socket.io大致一致,仅仅提供对websocket的客户端的简单包装,若是Android 上原生浏览器,没有安装Flash Lite情况下,就无能为力了。
因此,仅仅凭借Websocket + Flashsocket,是不能够完成跨浏览器、统一客户端API的重任。
socket.io通信传输协议
socket.io 支持以下通信信道传输协议:WebSocket
Adobe® Flash® Socket
AJAX long polling
AJAX multipart streaming
Forever Iframe
JSONP Polling
socket.io客户端和服务器端双方约定适合当前浏览器的最佳通信信道,然后正常通信。毫无疑问,基于全双工通信信道的Websocket/Flashsocket传输协议,是数据传输最为快速的选择,仅仅需要一个长连接。
基于上面图表,我们在指定socket.io transport参数时,可以做到心里有数。
在socketio-netty服务器端配置:
transports = websocket,flashsocket,htmlfile,xhr-polling,jsonp-polling
在客户端,简单定义地址:
var socket = io.connect('http://localhost:9000');
在不远的将来,桌面版浏览器可能升级了最新版本的websocket草案,导致客户端原生的websocket协议无法被识别时,可使用Flashsocket作为替代品。但总会有一种通信协议垫底,可以保证正常的运转。
在线画板示范
一个聊天的示范实时的数据量不大,那么一个在线画板应用呢,大家所绘制的线和点能够立刻的同步到所有人的屏幕上去。嗯,它还是跨越目前所见的浏览器(IE6+,Firefox,Opera,Safari,Chrome等),支持Phonegap构建,支持iphone,android,ipad等。因为没有部署的在线服务器,只能看一下简单视频了:
服务器端实现也是很简单,核心代码不到100行(不包括main函数、日志输出等):
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 | /** * 在线画报socket.io服务器端示范 * * @author yongboy * @time 2012-3-27 * @version 1.0 */public class WhiteboardServer { public static void main(String[] args) { MainServer chatServer = new MainServer(new WhiteboardHandler(), 80); chatServer.start(); }} class WhiteboardHandler extends IOHandlerAbs { private Logger log = Logger.getLogger(this.getClass()); // 房间的一对多<房间号,List<客户端>> private ConcurrentMap<String, Set<IOClient>> roomClients = new ConcurrentHashMap<String, Set<IOClient>>(); @Override public void OnConnect(IOClient client) { log.debug("A user connected :: " + client.getSessionID()); String content = String.format("5:::{\"name\":\"%s\",\"args\":[%s]}", "clientId", String.format("{\"id\":\"%s\"}", client.getSessionID())); client.send(content); } @Override public void OnDisconnect(IOClient client) { log.info("A user disconnected :: " + client.getSessionID() + " :: hope it was fun"); GenericIO genericIO = (GenericIO) client; Object roomObj = genericIO.attr.get("room"); if (roomObj == null) { log.info("the roomObj is null!"); return; } String roomId = roomObj.toString(); Set<IOClient> clients = roomClients.get(roomId); log.info("clients size is " + clients.size()); clients.remove(client); log.info("removed clients's size is " + clients.size()); // 通知其它客户端,有人离线 broadcastRoom(roomId, client, "roomCount", String.format( "{\"room\":\"%s\",\"num\":%s}", roomId, clients.size())); } @Override public void OnMessage(IOClient client, String oriMessage) { log.debug("Got a message :: " + oriMessage + " :: echoing it back to :: " + client.getSessionID()); String jsonString = oriMessage.substring(oriMessage.indexOf('{')); JSONObject jsonObject = JSON.parseObject(jsonString); String eventName = jsonObject.get("name").toString(); JSONArray argsArray = jsonObject.getJSONArray("args"); JSONObject obj = argsArray.getJSONObject(0); String roomId = obj.getString("room"); if (eventName.equals("roomNotice")) { if (!roomClients.containsKey(roomId)) { roomClients.put(roomId, new HashSet<IOClient>()); } GenericIO genericIO = (GenericIO) client; genericIO.attr.put("room", roomId); roomClients.get(roomId).add(client); int clientNums = roomClients.get(roomId).size(); broadcastRoom(roomId, client, "roomCount", String.format( "{\"room\":\"%s\",\"num\":%s}", roomId, clientNums)); String content = String.format( "5:::{\"name\":\"%s\",\"args\":[%s]}", "roomCount", String .format("{\"room\":\"%s\",\"num\":%s}", roomId, clientNums)); client.send(content); return; } broadcastRoom(roomId, client, eventName, obj.toJSONString()); } private void broadcastRoom(String roomId, IOClient client, String eventName, String jsonString) { Set<IOClient> clients = roomClients.get(roomId); if (clients == null || clients.isEmpty()) return; String content = String.format("5:::{\"name\":\"%s\",\"args\":[%s]}", eventName, jsonString); for (IOClient rc : clients) { if (rc == null || rc.getSessionID().equals(client.getSessionID())) { continue; } rc.send(content); } } @Override public void OnShutdown() { log.debug("shutdown now ~~~"); }} |
Gist brought to you by GitHub.
如何让打包的android支持websocket协议,可参考:为Phonegap Android平台增加websocket支持,使默认成为socket.io首选通道选择
本人暂无JAVA主机,无法部署到互联网环境下。只能截个图,看看先。
项目演示代码下载地址
小结
很显然,实时Web,是一种技术趋势,将成为一种人们的默认技术选择,用以拉近和桌面应用的距离。socket.io是一种数据实时推送、事件驱动模型的框架,支持事件订阅,简单易用。其价值目前看来,还未被完整的挖掘出来。
socket.io即提供了node.js服务器端(地址)又提供了客户端(地址)的整体解决方案,而socketio-netty则是基于JAVA服务器端,支持最新socket.io
client最新版规范。对JAVA编程人员来讲,可以不用学习node.js,从而多了一个选择。
这里再解释一下,为何构建app而不是webapp的服务器端:
Tomcat 7 虽然支持了Websocket协议,仅采用最新websocket草案版本
Jetty 8 已经支持Websocket,但才支持servlet 3.0规范
被绑定在某个单独的Servlet容器上面,不为通用
Servlet容器协议栈可能过于庞杂
参考资料
实时Web时代即将到来:不只谷歌Twitter玩得起http://tech.qq.com/a/20120521/000296.htm
文章转载自http://www.blogjava.net/yongboy/archive/2012/05/24/378839.html
相关文章推荐
- 构建实时Web的JAVA选择组合:socket.io client + socketio-netty server
- [Java] Netty Websocket Server Javascript Client
- [Java] Netty Websocket Server Javascript Client
- springmvc+maven+netty-socketio服务端构建实时通信
- springmvc+maven+netty-socketio服务端构建实时通信
- Perl IO:Socket IO:Select server client
- Socket Programming : How to Integrate Socket.io java Client in your Android App without Maven
- java|android 使用socket.io-client连接nodejs websocket
- php socket IO阻塞方式的Server/Client
- Java WebSocket客户端java WebSocketClient
- Java Notes-14(DateAtHost Client, TinyHttpd Server, Socket Options)
- 来段代码提提神-Java实现SocketServer和client链接
- java websocket @ServerEndpoint注解说明
- C++ client和node.js server的应用 : socket.io-chat-with-native
- Java WebSocket客户端java WebSocketClient
- 基于netty-socketio的web推送服务
- Java WebSocket客户端java WebSocketClient
- java使用socket上传文件,实现server端和client端
- Office Web Apps Server作为Client,Java代码作为Host实现Office在线预览'
- Java用WebSocket + tail命令实现Web实时日志