html5利用websocket完成的推送功能(tomcat)

利用websocket和java完成的消息推送功能,服务器用的是tomcat7.0.42,一些东西是自己琢磨的,也不知道恰不恰当,不恰当处,还请各位见谅,并指出。

程序简单来说,就是客户A可以发送消息给客户B,但有很多可以扩展的地方,

比如

1.如果加入数据库后,A发消息时客户B未上线,服务端将会把消息存在数据库中,等客户B上线后,在将消息取出发送给客户B

2.服务端也可发送消息到任意客户端上。

程序的运行效果截图如下(在chrome,搜狗,firefox下测试通过):代码将在最后给出

首先我们打开一个浏览器,显示输入您的名字,这里我输入soar

在打开第二个浏览器,这里我输入bill

这是如果我发送hello bill i am soar给bill,点击send

在另一个浏览器上就可以看到

Websocket

1.websocket是什么?

WebSocket是为解决客户端与服务端实时通信而产生的技术。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,

此后服务端与客户端通过此TCP连接进行实时通信。

2.websocket的优点

以前我们实现推送技术,用的都是轮询,在特点的时间间隔有浏览器自动发出请求,将服务器的消息主动的拉回来,在这种情况下,我们需要不断的向服务器发送请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽和服务器资源。会占用大量的带宽和服务器资源。

WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。在建立连接之后,服务器可以主动传送数据给客户端。

此外,服务器与客户端之间交换的标头信息很小。

WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;

关于ajax,comet,websocket的详细介绍,和websocket报文的介绍,大家可以参看http://www.shaoqun.com/a/54588.aspx  网页设计]Ajax、Comet与Websocket,

我如果以后有时间,也会写出来的

3.如何使用websocket

客户端

在支持WebSocket的浏览器中,在创建socket之后。可以通过onopen,onmessage,onclose即onerror四个事件实现对socket进行响应

一个简单是示例

  1. var ws = new WebSocket(“ws://localhost:8080”);
  2. ws.onopen = function()
  3. {
  4. console.log(“open”);
  5. ws.send(“hello”);
  1. };
  2. ws.onmessage = function(evt)
  3. {
  4. console.log(evt.data)
  5. };
  6. ws.onclose = function(evt)
  7. {
  8. console.log(“WebSocketClosed!”);
  9. };
  10. ws.onerror = function(evt)
  11. {
  12. console.log(“WebSocketError!”);
  13. };

1.var ws = new WebSocket(“ws://localhost:8080”);

申请一个WebSocket对象,参数是需要连接的服务器端的地址,同http协议使用http://开头一样,WebSocket协议的URL使用ws://开头,另外安全的WebSocket协议使用wss://开头。

ws.send(“hello”);

用于叫消息发送到服务端

2.ws.onopen = function() { console.log(“open”)};

当websocket创建成功时,即会触发onopen事件

3.ws.onmessage = function(evt) { console.log(evt.data) };

当客户端收到服务端发来的消息时,会触发onmessage事件,参数evt.data中包含server传输过来的数据

4.ws.onclose = function(evt) { console.log(“WebSocketClosed!”); };

当客户端收到服务端发送的关闭连接的请求时,触发onclose事件

5.ws.onerror = function(evt) { console.log(“WebSocketError!”); };

如果出现连接,处理,接收,发送数据失败的时候就会触发onerror事件

我们可以看出所有的操作都是采用事件的方式触发的,这样就不会阻塞UI,使得UI有更快的响应时间,得到更好的用户体验。

服务端

现在有很多的服务器软件支持websocket,比如node.js,jetty,tomcat等

这里我使用的是tomcat-7.0.42和eclipse4.2

在tomcat下使用websocket首先需要导入相关的jar

tomcat7提供的与WebSocket相关的类均位于包org.apache.catalina.websocket之中(包org.apache.catalina.websocket的实现包含于文件catalina.jar之中

这里我们把tomcat的全部导入就行了

在build path->configure build path->librarise->add library->server runtime->apache tomcat v7.0

同时需要import以下包

import org.apache.catalina.websocket.MessageInbound; 
import org.apache.catalina.websocket.StreamInbound; 
import org.apache.catalina.websocket.WsOutbound; 
import org.apache.catalina.websocket.WebSocketServlet;

我们需要两个类

第一个用于处理websocket请求

第二个用于处理每一次具体的WebSocket任务

第一个类

  1. public class SocketServer extends WebSocketServlet {
  2. private static final long serialVersionUID = 1L;
  3. //……
  4. @Override
  5. protected StreamInbound createWebSocketInbound(String arg0,
  6. HttpServletRequest arg1) {
  7. // TODO Auto-generated method stub
  8. return new ChatWebSocket(users);
  9. }
  10. }

这个Servlet继承自WebSocketServlet,实现createWebSocketInbound方法。该方法返回第二个类的实例。

第二个类

  1. public class ChatWebSocket extends MessageInbound {
  2.  
  3. @Override
  4. protected void onTextMessage(CharBuffer message) throws IOException {
  5.  
  6. }
  7.  
  8. @Override
  9. protected void onOpen(WsOutbound outbound) {
  10.  
  11. }
  12.  
  13. @Override
  14. protected void onClose(int status) {
  15.  
  16. }
  17.  
  18. @Override
  19. protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
  20.  
  21. }
  22. //其余略
  23.  
  24. }

protected void onTextMessage(CharBuffer message) throws IOException { }

文本消息响应

protected void onBinaryMessage(ByteBuffer arg0) throws IOException { }

二进制消息响应

protected void onOpen(WsOutbound outbound) { }

建立连接的触发的事件

protected void onClose(int status) { }

关闭连接时触发的事件

4.程序代码

html部分

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <script type="text/javascript" src="js/jquery.js"></script>
  6. <script type="text/javascript" src="js/socket.js"></script>
  7. <title>无标题文档</title>
  8. </head>
  9. <script language="javascript">
  10.  
  11. </script>
  12. <body>
  13. <table>
  14. <tr>
  15. <td>Message</td>
  16. <td><input type="text" id="message"></td>
  17. </tr>
  18. <tr>
  19. <td>Name</td>
  20. <td><input type="text" id="othername"></td>
  21. </tr>
  22. <tr>
  23. <td><input id="sendbutton" type="button" value="send" onClick="click" disabled="true">
  24. </input></td>
  25. </tr>
  26. </table>
  27. <script>
  28.  
  29. </script>
  30. </body>
  31. </html>

js部分(关于jquery部分不进行讲解)

  1. var username = window.prompt("输入你的名字:");
  2.  
  3. document.write("Welcome<p id=\"username\">"+username+"</p>");
  4.  
  5. if (!window.WebSocket && window.MozWebSocket)
  6. window.WebSocket=window.MozWebSocket;
  7. if (!window.WebSocket)
  8. alert("No Support ");
  9. var ws;
  10.  
  11. $(document).ready(function(){
  12.  
  13. $("#sendbutton").attr("disabled", false);
  14. $("#sendbutton").click(sendMessage);
  15.  
  16. startWebSocket();
  17. })
  18.  
  19. function sendMessage()
  20. {
  21. var othername=$("#othername").val();
  22. var msg="MSG\t"+username+"_"+othername+"_"+$("#message").val();
  23. send(msg);
  24. }
  25. function send(data)
  26. {
  27. console.log("Send:"+data);
  28. ws.send(data);
  29. }
  30. function startWebSocket()
  31. {
  32. ws = new WebSocket("ws://" + location.host + "/WebSocket/SocketServer");
  33. ws.onopen = function(){
  34. console.log("success open");
  35. $("#sendbutton").attr("disabled", false);
  36. };
  37. ws.onmessage = function(event)
  38. {
  39. console.log("RECEIVE:"+event.data);
  40. handleData(event.data);
  41. };
  42. ws.onclose = function(event) {
  43. console.log('Client notified socket has closed',event);
  44. };
  45.  
  46. }
  47.  
  48. function handleData(data)
  49. {
  50. var vals=data.split("\t");
  51. var msgType=vals[0];
  52. switch(msgType)
  53. {
  54. case "NAME":
  55. var msg=vals[1];
  56. var mes="NAME"+"\t"+msg+"_"+ username;
  57. send(mes);
  58. break;
  59. case "MSG":
  60. var val2s=vals[1].split("_");
  61. var from=val2s[0];
  62. var message=val2s[2];
  63. alert(from+":"+message);
  64. break;
  65. default:
  66. break;
  67.  
  68. }
  69. }

java部分

  1. import java.io.IOException;
  2. import java.nio.ByteBuffer;
  3. import java.nio.CharBuffer;
  4.  
  5. import javax.servlet.http.HttpServletRequest;
  6. import java.util.Set;
  7.  
  8. import java.util.concurrent.CopyOnWriteArraySet;
  9.  
  10. import org.apache.catalina.websocket.MessageInbound;
  11. import org.apache.catalina.websocket.StreamInbound;
  12. import org.apache.catalina.websocket.WsOutbound;
  13. import org.apache.catalina.websocket.WebSocketServlet;
  14.  
  15. public class SocketServer extends WebSocketServlet {
  16. private static final long serialVersionUID = 1L;
  17. public final Set<ChatWebSocket> users = new CopyOnWriteArraySet<ChatWebSocket>();
  18.  
  19. public static int USERNUMBER = 1;
  20. @Override
  21. protected StreamInbound createWebSocketInbound(String arg0,
  22. HttpServletRequest arg1) {
  23. // TODO Auto-generated method stub
  24. return new ChatWebSocket(users);
  25. }
  26. public class ChatWebSocket extends MessageInbound {
  27.  
  28. private String username;
  29. private Set<ChatWebSocket> users = new CopyOnWriteArraySet<ChatWebSocket>();;
  30.  
  31. public ChatWebSocket() {
  32.  
  33. }
  34.  
  35. public ChatWebSocket(Set<ChatWebSocket> users) {
  36. this.users = users;
  37. }
  38.  
  39. @Override
  40. protected void onTextMessage(CharBuffer message) throws IOException {
  41. // 这里处理的是文本数据
  42. }
  43.  
  44. public void onMessage(String data) {
  45. String[] val1 = data.split("\\t");
  46. if(val1[0].equals("NAME"))
  47. {
  48. String[] val2=val1[1].split("_");
  49. for(ChatWebSocket user:users){
  50. if (user.username.equals(val2[0])){
  51. user.username=val2[1];
  52. }
  53. }
  54. }
  55. else if(val1[0].equals("MSG"))
  56. {
  57. String[] val2=val1[1].split("_");
  58. for(ChatWebSocket user:users){
  59. if (user.username.equals(val2[1])){
  60. try {
  61. CharBuffer temp=CharBuffer.wrap(data);
  62. user.getWsOutbound().writeTextMessage(temp);
  63. } catch (IOException e) {
  64. // TODO Auto-generated catch block
  65. e.printStackTrace();
  66. }
  67. }
  68. }
  69. }
  70. else
  71. {
  72. System.out.println("ERROR");
  73. }
  74.  
  75. }
  76.  
  77. @Override
  78. protected void onOpen(WsOutbound outbound) {
  79. // this.connection=connection;
  80. this.username = '#' + String.valueOf(USERNUMBER);
  81. USERNUMBER++;
  82. try {
  83. String message = "NAME" + "\t" + this.username;
  84. CharBuffer buffer = CharBuffer.wrap(message);
  85. this.getWsOutbound().writeTextMessage(buffer);
  86. } catch (IOException e) {
  87. // TODO Auto-generated catch block
  88. e.printStackTrace();
  89. }
  90. users.add(this);
  91. }
  92.  
  93. @Override
  94. protected void onClose(int status) {
  95. users.remove(this);
  96.  
  97. }
  98.  
  99. @Override
  100. protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
  101.  
  102. }
  103.  
  104. }
  105.  
  106. }

解释

这里我的想法是

1 每个用户在访问的时候首先需要输入自己的名字,接着向服务端发送连接请求

2 服务端在接受到客户端的连接请求后,会new ChatWebSocket(users);用于处理这个请求,并把它加入在线的用户列表中,由于这个时候,服务端尚不知道客户的名字。它会给这个用户假定一个名字,#1,然后服务端会发送"NAME" + "\t" +“#1”给客户端,你叫什么?

3 客户端收到这个消息会知道,服务器在问自己叫什么名字,于是客户端会发送"NAME"+"\t"+“#1”+"_"+ 自己的名字到服务端,(我叫xxx)

4 服务端收到这个消息后根据#1在当前在线的用户列表中进行查找,将#1替换为客户的名字,这样服务端就知道了这个客户的名字了

5 当客户离开时,服务端会触发onClose事件,服务端会把当前用户从在线列表中移除

用图画出来类似这样(画的不好,—_—!!)

代码

js

  1. ws = new WebSocket("ws://" + location.host + "/WebSocket/SocketServer");

连接服务端

java

  1. protected StreamInbound createWebSocketInbound(String arg0,
  2. HttpServletRequest arg1) {
  3. // TODO Auto-generated method stub
  4. return new ChatWebSocket(users);
  5. }

创建一个chatwebsocket用于处理这个请求,触发该chatwebsocket对象的onOpen事件

  1. @Override
  2. protected void onOpen(WsOutbound outbound) {
  3. // this.connection=connection;
  4. this.username = '#' + String.valueOf(USERNUMBER);
  5. USERNUMBER++;
  6. try {
  7. String message = "NAME" + "\t" + this.username;
  8. CharBuffer buffer = CharBuffer.wrap(message);
  9. this.getWsOutbound().writeTextMessage(buffer);
  10. } catch (IOException e) {
  11. // TODO Auto-generated catch block
  12. e.printStackTrace();
  13. }
  14. users.add(this);
  15. }

为这个客户假定一个姓名,并发送NAME+“\t”+假定的姓名  给该客户端,同时将该客户端加入当前连接的客户列表中

js

  1. function handleData(data)
  2. {
  3. var vals=data.split("\t");
  4. var msgType=vals[0];
  5. switch(msgType)
  6. {
  7. case "NAME":
  8. var msg=vals[1];
  9. var mes="NAME"+"\t"+msg+"_"+ username;
  10. send(mes);
  11. break;
  12. //………
  13. }
  14. }

接受并处理服务端发来到的消息,发现是服务端问自己叫什么名字,于是发送”NAME"+"\t"+假定的名字+"_"+ 真正的名字 给服务端

java

  1. public void onMessage(String data) {
  2. String[] val1 = data.split("\\t");
  3. if(val1[0].equals("NAME"))
  4. {
  5. String[] val2=val1[1].split("_");
  6. for(ChatWebSocket user:users){
  7. if (user.username.equals(val2[0])){
  8. user.username=val2[1];
  9. }
  10. }
  11. }
  12.  
  13. //………
  14. }

处理并接受客户端发来的消息,发现是客户端回复自己叫什么名字,于是在根据先前假定的名字在当前连接的客户列表中进行查找,将假名变成真名

js

  1. function sendMessage()
  2. {
  3. var othername=$("#othername").val();
  4. var msg="MSG\t"+username+"_"+othername+"_"+$("#message").val();
  5. send(msg);
  6. }

客户对另一个人发起对话,消息格式为:“MSG”+自己的名字+_+对方的名字+_+消息

java

  1. public void onMessage(String data) {
  2. ///…………
  3. else if(val1[0].equals("MSG"))
  4. {
  5. String[] val2=val1[1].split("_");
  6. for(ChatWebSocket user:users){
  7. if (user.username.equals(val2[1])){
  8. try {
  9. CharBuffer temp=CharBuffer.wrap(data);
  10. user.getWsOutbound().writeTextMessage(temp);
  11. } catch (IOException e) {
  12. // TODO Auto-generated catch block
  13. e.printStackTrace();
  14. }
  15. }
  16. }
  17. }
  18. ///…………
  19.  
  20. }

发现是客户发送的消息,根据对方的姓名,在当前连接的客户列表中查找,并将消息发给他

js

  1. function handleData(data)
  2. {
  3. var vals=data.split("\t");
  4. var msgType=vals[0];
  5. switch(msgType)
  6. {
  7. ///…
  8.  
  9. case "MSG":
  10. var val2s=vals[1].split("_");
  11. var from=val2s[0];
  12. var message=val2s[2];
  13. alert(from+":"+message);
  14. break;
  15. default:
  16. break;
  17.  
  18. }
  19. }

发现是另一个客户发来的消息,通过alert显示出来

java

  1. @Override
  2. protected void onClose(int status) {
  3. users.remove(this);
  4.  
  5. }

发现客户离开了,将客户从连接的客户列表中移除

可以改进的地方

1.若客户端A发送消息给B时,B不在线,可将消息存入数据库中,当发现B上线时,从数据库中取出,发送给B

2 服务端发送你叫什么时,可加入超时机制,若客户端一定时间内没有回复自己叫什么,则可将该客户从在线列表中删掉

程序下载地址:http://files.cnblogs.com/magicsoar/WebSocket.rar

作者:magicsoar
联系方式:sungaofei008@163.com邮我邮我
qq:1021842556点我
 
 
标签: html5websocket

html5利用websocket完成的推送功能(tomcat)的更多相关文章

  1. html5利用websocket完成的推送功能

    利用websocket和java完成的消息推送功能,服务器用的是tomcat7.0,一些东西是自己琢磨的,也不知道恰不恰当,不恰当处,还请各位见谅,并指出. 程序简单来说,就是客户A可以发送消息给客户 ...

  2. HTML5与php实现消息推送功能

    1.html页面basic_sse.html <!DOCTYPE html> <html lang="en"> <head> <meta ...

  3. 拾人牙慧篇之——基于HTML5中websocket来实现消息推送功能

    一.写在前面 要求做一个,后台发布信息,前台能即时得到通知的消息推送功能.网上搜了也有很多方式,ajax的定时询问,Comet方式,Server-Sent方式,以及websocket.表示除了定时询问 ...

  4. HTML5 学习总结(五)——WebSocket与消息推送

    B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链 ...

  5. HTML5 学习笔记(五)——WebSocket与消息推送

    B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链 ...

  6. 基于Tomcat7、Java、WebSocket的服务器推送聊天室

    http://blog.csdn.net/leecho571/article/details/9707497 http://blog.fens.me/java-websocket-intro/ jav ...

  7. Tomcat学习总结(4)——基于Tomcat7、Java、WebSocket的服务器推送聊天室

    前言           HTML5 WebSocket实现了服务器与浏览器的双向通讯,双向通讯使服务器消息推送开发更加简单,最常见的就是即时通讯和对信息实时性要求比较高的应用.以前的服务器消息推送大 ...

  8. WebSocket与消息推送

    B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链 ...

  9. Asp.NET MVC 中使用 SignalR 实现推送功能

    一,简介Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请 ...

随机推荐

  1. Aladdin and the Flying Carpet(唯一分解定理)

    题目大意:给两个数a,b,求满足c*d==a且c>=b且d>=b的c,d二元组对数,(c,d)和(d,c)属于同一种情况: 题目分析:根据唯一分解定理,先将a唯一分解,则a的所有正约数的个 ...

  2. GUI:GUI的方式创建/训练/仿真/预测神经网络—Jason niu

    (1)导入数据:点击最左底部Import 按钮 (2)创建模型network_Jason_niu:点击底部的New按钮 (3)设置参数并训练:点击底部的Open按钮 (4)仿真预测: 大功告成!

  3. VS2017 下载离线MSDN文档

    VS2017 下载离线MSDN文档 点开帮助窗口的时候发现没有添加和删除帮助内容选项.处理方法如下: 1.打开vs2017安装包,如果你找不到安装包,可在相应你下载vs2017的浏览器上找到下载内容, ...

  4. SpringBoot整合elasticsearch

    在这一篇文章开始之前,你需要先安装一个ElasticSearch,如果你是mac或者linux可以参考https://www.jianshu.com/p/e47b451375ea,如果是windows ...

  5. [C程序设计基础]快速排序

    //从大到小排序 ///三个参数 a要排序的 数组, l扫左边的 r扫右边 void quickSort(int a[],int l, int r){ /// 左边要小于 右边才有意义 if (l & ...

  6. [蓝点ZigBee] Zstack 之点亮LED灯 ZigBee/CC2530 视频资料

    LED点灯实验,主要是依据Zstack 现有程序修改LED相关驱动,适配到我们自己的开发板上,我们开发板共有4个LED灯,其中一个是电源指示灯,剩余3个都是GPIO控制的LED灯,有LED 灯连接方式 ...

  7. JDBC连接

    jdbc是java中的数据库连接技术,功能非常强大. 数据库访问过程 1.加载数据库驱动 要通过jdbc去访问某数据库必须有相应的JDBC driver 它往往由数据库厂商提供,是链接jdbc API ...

  8. vim技巧3

    yyp复制当前行到下一行ddp剪切当前行到下一行cw:删除当前单词并进入插入模式xp:交换当前字符和右边字符s:删除光标所在的字符并进入插入模式I:在行首开始输入文字并进入插入模式A:在行尾开始输入文 ...

  9. 3ds max学习笔记(二)--查看视点

    查看视点 文件 --打开 --指南文件--坦克(.max文件即可) 1.利用透视图(和眼睛看到的世界很相似)查看 2.alt+w :最大化显示(最大化视角切换按钮: ) 3.缩放视点:滚动鼠标滚轮;匀 ...

  10. sweetalert的使用

    1.swal()方法中的参数: 2.引入css与js,通过cdn加速服务 <link href="https://cdnjs.cloudflare.com/ajax/libs/swee ...