WebSocket实例—初级聊天室(来自Tomcat8的examples)
来源:互联网 发布:数字移相算法 编辑:程序博客网 时间:2024/06/03 13:49
程序跑起来
在Tomcat的Webapps中自带有Tomcat的很多小例子。本文选取其中的关于WebSocket的例子,来进行学习。首先先将程序跑起来。
开发环境eclipse+tomcat8
1、新建项目名称为examples(自取名字也可以,但是在程序中也要更改,这里避免麻烦,就不该了)
2、将websocket文件夹拷贝到WebContent目录下
3、将WEB-INF/classes文件夹中websocket和util包拷贝到src目录下
4、导入必要的包,我缺的是juli.jar包,右键-》build path-》configure build path-》add External JARs,juli包在tomcat的bin目录下。
配置Tomcat步骤省略了,运行项目,在浏览器中输入
http://localhost:8080/examples/websocket/chat.xhtml
即能实现浏览器之间的对话。
运行如下所示:(注意我这里面改变了项目名,程序中也做了相应的改变)
程序分析
这样就实现了初级的聊天程序,我们再来分析一下源代码。
我们发现该段代码是基于注解的实现。注解是元数据,对代码进行说明。但是不影响代码的逻辑功能。我们先看一下这段代码大概实现了一个什么样的逻辑。
1、定义一下基本的变量信息,表示在线客户端的信息。定义了一个Set来保存会话连接。
2、当连接打开时,保存连接,并广播连接加入信息。
3、当服务器端接收到客户端的信息时,将信息进行广播。
4、当连接关闭时,广播连接关闭信息
5、对错误的处理。
然后,我们发现最核心的功能就是,
建立连接-》将连接保存在set中-》广播信息-》连接断开-》将连接从set中移除
服务器端
@ServerEndpoint(value = "/websocket/chat")public class ChatAnnotation { private static final Log log = LogFactory.getLog(ChatAnnotation.class); private static final String GUEST_PREFIX = "Guest"; private static final AtomicInteger connectionIds = new AtomicInteger(0); private static final Set<ChatAnnotation> connections = new CopyOnWriteArraySet<>(); private final String nickname; private Session session; public ChatAnnotation() { nickname = GUEST_PREFIX + connectionIds.getAndIncrement(); } @OnOpen public void start(Session session) { this.session = session; connections.add(this); String message = String.format("* %s %s", nickname, "has joined."); broadcast(message); } @OnClose public void end() { connections.remove(this); String message = String.format("* %s %s", nickname, "has disconnected."); broadcast(message); } @OnMessage public void incoming(String message) { // Never trust the client String filteredMessage = String.format("%s: %s", nickname, HTMLFilter.filter(message.toString())); broadcast(filteredMessage); } @OnError public void onError(Throwable t) throws Throwable { log.error("Chat Error: " + t.toString(), t); } private static void broadcast(String msg) { for (ChatAnnotation client : connections) { try { synchronized (client) { client.session.getBasicRemote().sendText(msg); } } catch (IOException e) { log.debug("Chat Error: Failed to send message to client", e); connections.remove(client); try { client.session.close(); } catch (IOException e1) { // Ignore } String message = String.format("* %s %s", client.nickname, "has been disconnected."); broadcast(message); } } }}
我们的疑惑可以有以下几点:
1、注解所发挥的作用
2、CopyOnWriteArraySet功能
3、发送信息时为什么是 client.session.getBasicRemote().sendText(msg);
第一个问题
程序上的注解都有以下几个,了解它们最好的方式就是看开发者文档。
@ServerEndpoint(value = “/websocket/chat”)
@ServerEndPoint注释端点表示将WebSocket服务器运行在ws://[Server端IP或域名]:[Server端口]/websockets/echo的访问端点,客户端浏览器已经可以对WebSocket客户端API发起HTTP长连接了。使用ServerEndpoint注释的类必须有一个公共的无参数构造函数。
@OnOpen
方法级别的注解,用于一个新的websocket会话连接打开时,注解方法的回掉
@OnClose
同上
@OnError
同上
@OnMessage
@onMessage注解的Java方法用于接收传入的WebSocket的信息,这个信息可以是文本格式的,也可以是二进制格式
第二个问题
参考链接:http://ifeve.com/tag/copyonwritearrayset/
CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
第三个问题
那我们先看一下session的含义。
它是一个接口,表示两个web socket端点之间的对话。
getBasicRemote()的含义是:返回一个引用,什么样的引用呢?一个远程端点对象的引用,这个远程端点,代表会话的一端,能够同步的给另一端发送消息。
客户端
<script type="application/javascript"><![CDATA[ "use strict"; var Chat = {}; Chat.socket = null; //判断浏览器是否支持websocket,支持就新建websocket对象,不支持就输出错误信息。 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初始化,与服务器建立连接 Chat.initialize = function() { if (window.location.protocol == 'http:') { Chat.connect('ws://' + window.location.host + '/Test/websocket/chat'); } else { Chat.connect('wss://' + window.location.host + '/Test/websocket/chat'); } }; //发送消息 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; }); Chat.initialize(); document.addEventListener("DOMContentLoaded", function() { // Remove elements with "noscript" class - <noscript> is not allowed in XHTML var noscripts = document.getElementsByClassName("noscript"); for (var i = 0; i < noscripts.length; i++) { noscripts[i].parentNode.removeChild(noscripts[i]); } }, false); ]]></script>
- WebSocket实例—初级聊天室(来自Tomcat8的examples)
- WebSocket入门教程(五)-- WebSocket实例:简单多人聊天室
- WebSocket聊天室的实现
- Netty+websocket的客服聊天室
- websocket实现简单的聊天室
- 基于WebSocket的简易聊天室
- webSocket简单聊天室(Java_Demo)
- IM聊天室(一):WebSocket
- eclipse和tomcat8的websocket入门篇
- 使用Tomcat8实现WebSocket的简单例子
- tomcat7和tomcat8的websocket区别
- Tomcat学习总结(4)——基于Tomcat7、Java、WebSocket的服务器推送聊天室
- 简单又好用的聊天室技术——WebSocket
- WebSocket 聊天室
- WebSocket聊天室
- websocket聊天室
- websocket聊天室
- websocket聊天室
- 商务通通过JS获取sid、cid等参数
- oracle 数据更新讲解
- Java 多线程 并发编程
- MFC单文档视图之图标资源加载及绘制
- CaffeNet C++ Classification 例子运行方法
- WebSocket实例—初级聊天室(来自Tomcat8的examples)
- android监测用户刚刚拍照
- 关键词研究
- Hbase-1.1.2 Java API 操作
- duoj Almost sorted interval 单调队列
- [Java]剑走偏锋的10条编程技巧
- C语言实现大整数乘法代码的完整代码及运行结果
- 图片下面加字排版
- 爱在心中