“服务器推”之websocket实现之简单聊天室
来源:互联网 发布:淘宝网店卖的钱在哪里 编辑:程序博客网 时间:2024/05/16 13:44
最近在学习Server-push的一些技术,websocket当然也要简单学习一下。
一个简单的websocket实现聊天室的例子:
websocket在tomcat中只有tomcat7支持,tomcat7以下的是没实现这个功能,而tomcat7以上的则是将其remove了,tomcat团队只是对version6中的一个bug作修复,不再继续开发,原因是被JSR356 websocket1.1的实现给代替了。
不过服务端使用JSR356的实现来开发websocket 服务端很方便,浏览器端使用websocket javascript api来编写也很简单方便,不足之处是浏览器对javascript websocket的支持还没那么广泛(Firefox39,chrome38和360都可以,ie8不行,其中360虽然是IE内核,但是它有自己的使用模块)。
IE不支持的解决方案:利用Flash实现websocket的通信功能,其实现请可以参照这位网友的代码:
点击打开链接
点击打开链接
websocket javascript api:websocket javascript api
一、websocket Server端基于annotation的实现
package org.wz.jsrapi.websocket.server;import java.io.IOException;import java.util.Calendar;import java.util.Set;import java.util.concurrent.CopyOnWriteArraySet;import java.util.concurrent.atomic.AtomicInteger;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;/** * * @author wz * 基于annotation的实现 */@ServerEndpoint(value = "/wsWithAnnotation")public class WebsocketServerWithAnnotation {private static final Calendar cl = Calendar.getInstance();private static final String NICK_PREFIX = "user";private static final AtomicInteger connectionIds = new AtomicInteger(0);private static final Set<WebsocketServerWithAnnotation> connections = new CopyOnWriteArraySet<WebsocketServerWithAnnotation>();private final String nickname;private Session session;public WebsocketServerWithAnnotation() {nickname = NICK_PREFIX + connectionIds.getAndIncrement();}@OnOpenpublic void open(Session session) {this.session = session;String message = String.format("%1$tF %1$tT %2$s ", cl, this.nickname + "joined!");connections.add(this);broadcast(message);}@OnMessagepublic void handleMessage(String message) {String newmessage = String.format("%1$tF %1$tT %2$s %3$s", cl, this.nickname, message);broadcast(newmessage);}@OnClosepublic void end() {connections.remove(this);String message = String.format("%1$tF %1$tT %2$s %3$s", cl, this.nickname, "has disconnected.");broadcast(message);}@OnErrorpublic void onError(Session session,Throwable t) throws Throwable {System.err.println("chat error " + t.toString());}public static void broadcast(String message) {for (WebsocketServerWithAnnotation ws : connections) {try {synchronized (ws) {ws.session.getBasicRemote().sendText(message);}} catch (IOException e) {try {ws.session.close();} catch (IOException e1) {}connections.remove(ws);broadcast(String.format("%1$tF %1$tT %2$s %3$s", cl, ws.nickname, "has been disconnected."));}}}}
二、基于继承Endpoint的实现
package org.wz.jsrapi.websocket.server;import java.io.IOException;import java.util.Calendar;import java.util.Set;import java.util.concurrent.CopyOnWriteArraySet;import java.util.concurrent.atomic.AtomicInteger;import javax.websocket.CloseReason;import javax.websocket.Endpoint;import javax.websocket.EndpointConfig;import javax.websocket.MessageHandler;import javax.websocket.Session;/** * * @author wz * 基于继承Endpoint的实现 */public class WebsocketServerInheritEndpoint extends Endpoint {private static final Calendar cl = Calendar.getInstance();private static final String NICK_PREFIX = "user";private static final AtomicInteger connectionIds = new AtomicInteger(0);private static final Set<WebsocketServerInheritEndpoint> connections = new CopyOnWriteArraySet<WebsocketServerInheritEndpoint>();private final String nickname;private Session session;public WebsocketServerInheritEndpoint() {nickname = NICK_PREFIX + connectionIds.getAndIncrement();}//没有onmessage方法,在建立连接后由MessageHandler处理public void onOpen(Session session, EndpointConfig config) {this.session = session;String message = String.format("%1$tF %1$tT %2$s ", cl, this.nickname + " joined!");connections.add(this);session.addMessageHandler(new ChatMessageHandler());broadcast(message);}//移到ChatMessageHandler中去//public void handleMessage(String message) {//String newmessage = String.format("%1$tF %1$tT %2$s %3$s", cl, this.nickname, message);//broadcast(newmessage);//}@Overridepublic void onClose(Session session1, CloseReason closereason) {connections.remove(this);String message = String.format("%1$tF %1$tT %2$s %3$s", cl, this.nickname, "has disconnected.");broadcast(message);}@Overridepublic void onError(Session session, Throwable t) {System.err.println("chat error " + t.toString());}public static void broadcast(String message) {for (WebsocketServerInheritEndpoint ws : connections) {try {synchronized (ws) {ws.session.getBasicRemote().sendText(message);}} catch (IOException e) {try {ws.session.close();} catch (IOException e1) {}connections.remove(ws);broadcast(String.format("%1$tF %1$tT %2$s %3$s", cl, ws.nickname, "has been disconnected."));}}}private class ChatMessageHandler implements MessageHandler.Whole<String> {@Overridepublic void onMessage(String message) {String formatMessage = String.format("%1$tF %1$tT %2$s %3$s", cl, nickname, message);broadcast(formatMessage);}}}
三、部署配置类
package org.wz.jsrapi.websocket.config;import java.util.HashSet;import java.util.Set;import javax.websocket.Endpoint;import javax.websocket.server.ServerApplicationConfig;import javax.websocket.server.ServerEndpointConfig;import org.wz.jsrapi.websocket.server.WebsocketServerInheritEndpoint;/** * * @author wz * * 将websocket应用部署在web应用里的配置: * 1.要实现ServerApplicationConfig接口 * 2.使用web容器的扫描机制[在servlet3.0中定义的]来扫描websocket的实现类 * 3.一个容器中可以有多个ServerApplicationConfig */public class WebsocketDeployConfig implements ServerApplicationConfig{/** * 扫描部署文件被加以@ServerEndPoint的class(可以写上自己的过滤代码),由容器调用 * */@Overridepublic Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> set) {//不作过滤了,直接返回set(其实里面就一个:WebsocketServerWithAnnotation)return set;}/** * 扫描部署文件中继承Endpoint的class(可以写上自己的过滤代码),由容器调用 * 参数是Endpoint的子类集合,返回的是ServerEndpoint的集合,所以我们要在其中作处理的 * */@Overridepublic Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> set) {Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>();//只写了这么一个,指定其访问path:/wsInheritEndpoint就Build它就OK了if(set.contains(WebsocketServerInheritEndpoint.class)){result.add(ServerEndpointConfig.Builder.create(WebsocketServerInheritEndpoint.class, "/wsInheritEndpoint").build());}return result;}}
四、HTMLclient端
<html><head><title>websocket test: chat</title><style type="text/css">input#chat {width: 410px}#console-container {width: 400px;}#console {border: 1px solid #CCCCCC;border-right-color: #999999;border-bottom-color: #999999;height: 170px;overflow-y: scroll;padding: 5px;width: 100%;}#console p {padding: 0;margin: 0;}</style><script type="text/javascript"> var Chat = {}; Chat.socket = null; Chat.connect = (function(host) { if ('WebSocket' in window) { Chat.socket = new WebSocket(host); } else if ('MozWebSocket' in window) { Chat.socket = new MozWebSocket(host); } else { Console.log('Error: WebSocket is not supported by this browser.'); return; } Chat.socket.onopen = function () { Console.log('Info: WebSocket connection opened.'); document.getElementById('chat').onkeydown = function(event) { if (event.keyCode == 13) { Chat.sendMessage(); } }; }; Chat.socket.onclose = function () { document.getElementById('chat').onkeydown = null; Console.log('Info: WebSocket closed.'); }; Chat.socket.onmessage = function (message) { Console.log(message.data); }; Chat.socket.onerror = function (){ Chat.socket.close(1000); Console.log('Info: WebSocket happened error!.'); }; }); Chat.initialize = function() { if (window.location.protocol == 'http:') { Chat.connect('ws://' + window.location.host + '/websocket_jsr356/wsInheritEndpoint'); //两种服务端实现方式切换 //Chat.connect('ws://' + window.location.host + '/websocket_jdk/wsWithAnnotation'); } else { Chat.connect('wss://' + window.location.host + '/websocket_jsr356/wsInheritEndpoint'); //两种服务端实现方式切换 //Chat.connect('wss://' + window.location.host + '/websocket_jdk/wsWithAnotation'); } }; //在直接关闭页面在chrome下会触发error事件,unload的时候调用websocket.close()显示关闭即可。 Chat.close = (function(){ Chat.socket.close(1000);//正常关闭,code=1000 Console.log('Info: WebSocket closed!'); }); Chat.sendMessage = (function() { var message = document.getElementById('chat').value; if (message != '') { Chat.socket.send(message); document.getElementById('chat').value = ''; } }); var Console = {}; Console.log = (function(message) { var console = document.getElementById('console'); var p = document.createElement('p'); p.style.wordWrap = 'break-word'; p.innerHTML = message;console.appendChild(p); while (console.childNodes.length > 25) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; }); if (window.attachEvent){ //其实这儿暂时没用,因为IE根本不支持基于HTML5的websocket window.attachEvent("onload", Chat.initialize); window.attachEvent("onunload", Chat.close); }else{ window.addEventListener("load", Chat.initialize, false); window.addEventListener("unload", Chat.close, false); } </script></head><body><p><input type="text" placeholder="type and press enter to chat"id="chat" /></p><div id="console-container"><div id="console" /></div></div></body></html>
参考资料:
http://tomcat.apache.org/tomcat-7.0-doc/websocketapi/index.html
https://jcp.org/aboutJava/communityprocess/final/jsr356/index.html
https://jcp.org/en/egc/view?id=356
另外,推荐一个学习网站:
http://ajaxpatterns.org/IFrame_Call
0 0
- “服务器推”之websocket实现之简单聊天室
- websocket实现简单的聊天室
- websocket 简介、实现简单聊天室
- TCP之实现简单聊天室
- WebSocket实现简单的web聊天室
- WebSocket实现简单的web聊天室
- WebSocket jfinal 实现简单的聊天室功能
- Netty结合WebSocket实现简单网页聊天室
- python之虚拟聊天室之简单的服务器
- iOS webSocket之单利简单实现即时通讯
- “服务器推”之Iframe配合comet实现
- WebSocket+Netty实现聊天室
- WebSocket实现网页聊天室
- WebSocket实现即时聊天室
- WebSocket + html 实现聊天室
- WebSocket聊天室的实现
- Web后台推技术之WebSocket初探
- HTML5 WebSocket(Client) + JavaWeb(Server) 实现简单的聊天室功能
- Android Binder 通信机制学习(四)
- 在SAE(新浪云平台)上使用 python django库编写网站
- VS2010新建项目失败
- Foundation --- 字符串的获取
- 经典50例,可以参考一下!
- “服务器推”之websocket实现之简单聊天室
- 怎么给文件夹加密
- Android开发adb命令含义
- R语言简介,环境配置与简易使用
- Verilog与SystemVerilog编程陷阱:如何避免101个常犯的编码错误
- Bootstrap + Font Awesome
- listview优化问题
- JAVA将图片以二进制形式存入Access数据库
- Windows安装Apache Server