本篇博客只是记录websocket在自己的项目中的应用,只是记录,不做说明(后来替换为GoEasy了)。

  1. /**
  2. * 握手的设置,这其实是为了获取session
  3. */
  4. public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
  5. @Override
  6. public void modifyHandshake(ServerEndpointConfig config,
  7. HandshakeRequest request,
  8. HandshakeResponse response) {
  9. HttpSession httpSession = (HttpSession) request.getHttpSession();
  10. config.getUserProperties().put(HttpSession.class.getName(), httpSession);
  11. }
  12. }
  1. /**
  2. * JSR356定义了WebSocket的规范,Tomcat7中实现了该标准。
  3. * JSR356 的 WebSocket 规范使用 javax.websocket.*的 API,
  4. * 可以将一个普通 Java 对象(POJO)使用 @ServerEndpoint 注释作为 WebSocket 服务器的端点。
  5. * value必须以"/"开始,是否已"/"结束无所谓,
  6. * configurator指的是ServerEndpointConfig 的配置信息,可以配置握手协议等信息,而在本例中是为了获取session
  7. */
  8. @ServerEndpoint(value = "/websocket/task", configurator = GetHttpSessionConfigurator.class)
  9. public class TaskServer {
  10.  
  11. private static Logger logger = LoggerFactory.getLogger(TaskServer.class);
  12.  
  13. //ConcurrentHashMap在线程安全的基础上提供了更好的写并发能力,但同时降低了对读一致性的要求
  14. private static final Map<String, Session> doctorMap = new ConcurrentHashMap<String, Session>();
  15.  
  16. //使用ServerEndpoint注释的类必须有一个公共的无参数构造函数
  17. public TaskServer() {
  18. }
  19.  
  20. @OnOpen
  21. public void onOpen(Session session, EndpointConfig config) {
  22. HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
  23. if (httpSession == null) {
  24. return;
  25. }
  26. // DoctorUser doctor = (DoctorUser) httpSession.getAttribute(Constants.SESSION_DOCTOR);
  27. Doctoruser doctor = (Doctoruser) httpSession.getAttribute(Constants.SESSION_DOCTOR_USER);
  28.  
  29. String doctorID = doctor.getId();
  30. logger.info("doctor " + doctor.getName() + " id = " + doctor.getId() + " 建立连接");
  31. doctorMap.put(doctorID, session);
  32. // attributes.put(Constants.WEBSOCKET_DOCTORNAME,userName);
  33. }
  34.  
  35. @OnClose
  36. public void onClose(Session session) {
  37. // doctorMap.remove( doctorID);
  38. boolean has = doctorMap.containsValue(session);
  39. String doctorId = null;
  40. if (has == true) {
  41. for (Map.Entry entry : doctorMap.entrySet()) {
  42. if (entry.getValue().equals(session)) {
  43. doctorId = (String) entry.getKey();
  44. doctorMap.remove(doctorId);
  45. }
  46. }
  47. } else {
  48. logger.info("on close error");
  49. }
  50. logger.info("doctor " + doctorId + " 断开连接");
  51. }
  52.  
  53. @OnMessage
  54. public void incoming(String message, Session session) {
  55. //logger.info("recv message: " + message);
  56. sendMessage("pong",session);
  57. }
  58.  
  59. @OnError
  60. public void onError(Throwable t) throws Throwable {
  61. logger.info("socket 连接错误 " + t.toString());
  62. }
  63.  
  64. //把消息推送给前端,在本例中推送是给doctorID推送message(数据库表中任务表的id)
  65. public static void broadcast(String doctorID, String message) {
  66. Session session = doctorMap.get(doctorID);
  67. if (session == null) {
  68. logger.warn("用户:" + doctorID + "socket连接不存在");
  69. return;
  70. }
  71.  
  72. session.getAsyncRemote().sendText(message); //非阻塞、异步
  73.  
  74. /*try {
  75. //详见 《 websocket getAsyncRemote()和getBasicRemote()区别》
  76. //http://blog.csdn.net/who_is_xiaoming/article/details/53287691
  77.  
  78. //session.getBasicRemote().sendText(message); //阻塞、同步
  79. session.getAsyncRemote().sendText(message); //非阻塞、异步
  80. } catch (IOException e) {
  81. logger.error("推送消息错误--" + e);
  82. doctorMap.remove(doctorID);
  83. try {
  84. session.close();
  85. } catch (IOException e1) {
  86. e1.printStackTrace();
  87. }
  88. }*/
  89. }
  90.  
  91. /**
  92. * 发送信息
  93. *
  94. * @param message 发送内容
  95. * @param session 用户session
  96. */
  97. public void sendMessage(String message, Session session) {
  98. try {
  99. synchronized (session) {
  100. if (session.isOpen()) {
  101. session.getBasicRemote().sendText(message);
  102. }
  103. }
  104. } catch (Exception e) {
  105. logger.error("send message exception", e);
  106. }
  107. }
  108.  
  109. public static boolean hasConnection(String doctorID) {
  110. if (doctorMap.get(doctorID) == null) return false;
  111. return true;
  112. }
  113.  
  114. public static List<String> getDoctorList() {
  115. ArrayList<String> doctors = new ArrayList<>();
  116. for (Map.Entry entry : doctorMap.entrySet()) {
  117. doctors.add((String) entry.getKey());
  118. }
  119. return doctors;
  120. }
  121.  
  122. public static Map<String, Session> getDoctorMap() {
  123. return doctorMap;
  124. }
  125. }
  1. <script type="text/javascript">
  2. /*
  3. 1.连接上之后,每秒发送一个心跳,服务器同样返回一个心跳,用来表示服务器没挂。
  4. 2.断线重连(我们测试的环境是断开网络连接),断开网络后,心跳包无法发送出去,所以如果当前时间距离上次成功心跳的时间超过20秒,说明连接已经出现问题了,此时需要关闭连接。
  5. 3.第一次关闭连接时websocket会尝试重连,设置了一个时间期限,10秒。10秒内如果能连上(恢复网络连接)就可以继续收发消息,连不上就关闭了,并且不会重连。
  6. 4.30秒内收不到服务器消息(心跳每秒发送),我就认为服务器已经挂了,就会调用close事件,然后进入第3步。
  7. */
  8. /*
  9. •一个定时器ws.keepAliveTimer,用来每秒发送一次心跳。
  10. •上次心跳成功的时间ws.last_health_time以及当前时间let time = new Date().getTime();。
  11. •断开连接(ws.close())时的时间reconnect,因为在close事件发生后需要重连10秒。
  12. •是否已经重连过reconnectMark。
  13. •断开连接(ws.close())时需要保存ws对象tempWs。我曾试图ws = { ...ws }发现会丢失绑定的事件。
  14. •一个定时时间为30秒的setTimeout定时器ws.receiveMessageTimer,用来表示服务器是否在30秒内返回了消息。
  15. */
  16.  
  17. var ws = null;
  18. var url = 'ws://' + window.location.host + "${rootPath}/websocket/task";
  19.  
  20. var queue = new Queue(); //js的队列先进先出,把推送任务放到里面
  21.  
  22. $(function () {
  23. connect(url);
  24. getTask();
  25. });
  26.  
  27. //==============================================推送================================================
  28. function connect(url) {
  29. // 用户登录了并且没有连接过websocket
  30. if ("${sessionScope.SESSION_DOCTOR_ACCOUNT.id}".length == 32) {
  31. ws = new WebSocket(url);
  32. ws.last_health_time = -1; // 上次心跳成功的时间
  33.  
  34. //保持连接
  35. ws.keepalive = function () {
  36. var time = new Date().getTime(); //当前时间
  37. /*断线重连(我们测试的环境是断开网络连接),断开网络后,心跳包无法发送出去,
  38. 所以如果当前时间距离上次成功心跳的时间超过20秒,说明连接已经出现问题了,此时需要关闭连接。*/
  39. if (ws.last_health_time !== -1 && time - ws.last_health_time > 20000) {
  40. ws.close();
  41. console.log("Info: connection closed.");
  42. } else {
  43. /*连接上之后,每秒发送一个心跳,服务器同样返回一个心跳,用来表示服务器没挂。
  44. ws.bufferedAmount === 0 && ws.readyState === 1 均表示连接是正常的*/
  45. if (ws.bufferedAmount === 0 && ws.readyState === 1) {
  46. ws.send("ping");
  47. ws.last_health_time = time;
  48. }
  49. }
  50. }
  51.  
  52. if (ws) {
  53. var reconnectTime = 0; //断开连接的时间
  54. var reconnectMark = false; //是否重连过
  55. ws.onopen = function () {
  56. reconnectTime = 0;
  57. reconnectMark = false;
  58. // 30s没收到信息,代表服务器出问题了,关闭连接。如果收到消息了,重置该定时器。
  59. ws.receiveMessageTimer = setTimeout(function () {
  60. ws.close();
  61. console.log("Info: connection closed.");
  62. }, 30000);
  63. // 为1表示连接处于open状态,keepAliveTimer用来每秒发送一次心跳;
  64. if (ws.readyState === 1) {
  65. ws.keepAliveTimer = setInterval(function () {
  66. ws.keepalive();
  67. }, 5000);
  68. }
  69. console.log("Info: connection opened. " + url);
  70. }
  71.  
  72. ws.onerror = function () {
  73. console.error("onerror");
  74. }
  75. ws.onmessage = function (event) {
  76. //console.log("Received:" + event.data+" "+new Date().getTime());
  77. //真正的逻辑代码
  78. if(event.data!="pong"){
  79. queue.push(event.data);
  80. playSound();
  81. $("#taskNum").html(queue.size());
  82. var src1 = $("#iframe").attr("src");
  83. if (src1 == "doctor/noTask.do") {
  84. srcValue("doctor/ecgTask.do");
  85. }
  86. }
  87.  
  88. // 收到消息,重置定时器
  89. clearTimeout(ws.receiveMessageTimer);
  90. // 30s没收到信息,代表服务器出问题了,关闭连接。
  91. ws.receiveMessageTimer = setTimeout(function () {
  92. ws.close();
  93. console.log("Info: connection closed.");
  94. }, 30000);
  95. }
  96.  
  97. ws.onclose = function () {
  98. clearTimeout(ws.receiveMessageTimer);
  99. clearInterval(ws.keepAliveTimer);
  100. // 如果没有重连过,进行重连。
  101. if (!reconnectMark) {
  102. reconnectTime = new Date().getTime();
  103. reconnectMark = true;
  104. }
  105. var tempWs = ws; // 保存ws对象
  106.  
  107. /*第一次关闭连接时websocket会尝试重连,设置了一个时间期限,10秒。
  108. 10秒内如果能连上(恢复网络连接)就可以继续收发消息,连不上就关闭了,并且不会重连。*/
  109. if (new Date().getTime() - reconnectTime >= 10000) {
  110. ws.close();
  111. console.log("Info: connection closed.");
  112. } else {
  113. ws = new WebSocket(url);
  114. ws.onopen = tempWs.onopen;
  115. ws.onmessage = tempWs.onmessage;
  116. ws.onerror = tempWs.onerror;
  117. ws.onclose = tempWs.onclose;
  118. ws.keepalive = tempWs.keepalive;
  119. ws.last_health_time = -1;
  120. }
  121. }
  122. } else {
  123. alert("This browser does not support webSocket");
  124. return false;
  125. }
  126. }
  127. }
  128.  
  129. <!--断开连接-->
  130. function disconnect() {
  131. if (ws!= null) {
  132. ws.close();
  133. ws = null;
  134. window.location = document.getElementsByTagName("base")[0].getAttribute("href")+ "doctor/logout.do";
  135. }
  136. }
  137.  
  138. <!--播放音乐-->
  139. function playSound() {
  140. var borswer = window.navigator.userAgent.toLowerCase();
  141. if (borswer.indexOf("ie") >= 0) {
  142. //IE内核浏览器
  143. var strEmbed = '<embed name="embedPlay" src="sounds/doctorTask.wav" autostart="true" hidden="true" loop="false"></embed>';
  144. if ($("body").find("embed").length <= 0)
  145. $("body").append(strEmbed);
  146. var embed = document.embedPlay;
  147. //浏览器不支持 audion,则使用 embed 播放
  148. embed.volume = 100;
  149. //embed.play();这个不需要
  150. } else {
  151. var audio = new Audio("sounds/doctorTask.wav");
  152. //audio.loop="loop";
  153. audio.play();
  154. }
  155. }
  156.  
  157. <!--onbeforeunload 事件在即将离开当前页面(刷新或关闭)时触发。-->
  158. window.onbeforeunload = signout;
  159. function signout() {
  160. disconnect();
  161. }
  162.  
  163. //改变iframe的src值
  164. function srcValue(val) {
  165. $("#iframe").attr("src", val);
  166. }
  167.  
  168. //退出
  169. function logout(){
  170. disconnect();
  171. $("#exitModal").modal("hide");
  172. }
  173. </script>

WebSocket推送的更多相关文章

  1. 用 Go 编写一个简单的 WebSocket 推送服务

    用 Go 编写一个简单的 WebSocket 推送服务 本文中代码可以在 github.com/alfred-zhong/wserver 获取. 背景 最近拿到需求要在网页上展示报警信息.以往报警信息 ...

  2. Golang websocket推送

    Golang websocket推送 在工作用主要使用的是Java,也做过IM(后端用的netty websocket).最近想通过Golang重写下,于是通过websocket撸了一个聊天室. 项目 ...

  3. 模拟websocket推送消息服务mock工具二

    模拟websocket推送消息服务mock工具二 在上一篇博文中有提到<使用electron开发一个h5的客户端应用创建http服务模拟后端接口mock>使用electron创建一个模拟后 ...

  4. GoEasy实现websocket 推送消息通知到客户端

    最近在实现一个推送功能,用户扫描二维码签到,后台及时将签到成功信息推送到浏览器端.排除了前端ajax轮询的方式,决定采用websocket及时推送. 于是发现了第三方websocket推送库GoEas ...

  5. 小谢第37问:关于websocket推送进度,本地保存进度条,然后跳出页面进入后再显示的问题

    1.主要技术点:sessionStorage 会话存储进度 这里在使用之前,顺便说一下cookie.sessionStorage.localStorage 共同点:都是保存在浏览器端,且同源的. 区别 ...

  6. 利用奇偶数来获取websocket推送时间间隔(或者比较前一个数和下一个数的变化)

    利用奇偶数来获取websocket推送时间间隔(或者比较前一个数和下一个数的变化) 在vue中的 data () {     return { countTime: 0,         newDat ...

  7. 基于Java的WebSocket推送

    WebSocket的主动推送 关于消息推送,现在的解决方案如轮询.长连接或者短连接,当然还有其他的一些技术框架,有的是客户端直接去服务端拿数据. 其实推送推送主要讲的是一个推的概念,WebSocket ...

  8. web全栈应用【爬取(scrapy)数据 -> 通过restful接口存入数据库 -> websocket推送展示到前台】

    作为 https://github.com/fanqingsong/web_full_stack_application 子项目的一功能的核心部分,使用scrapy抓取数据,解析完的数据,使用 pyt ...

  9. 从构建分布式秒杀系统聊聊WebSocket推送通知

    秒杀架构到后期,我们采用了消息队列的形式实现抢购逻辑,那么之前抛出过这样一个问题:消息队列异步处理完每个用户请求后,如何通知给相应用户秒杀成功? 场景映射 首先,我们举一个生活中比较常见的例子:我们去 ...

随机推荐

  1. Python编码问题小结

    开门见山 decode的作用是将其他编码的字符串转换成Unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成Unicode编码. encode的 ...

  2. Ubuntu下导入PySpark到Shell和Pycharm中(未整理)

    实习后面需要用到spark,虽然之前跟了edX的spark的课程以及用spark进行machine learning,但那个环境是官方已经搭建好的,但要在自己的系统里将PySpark导入shell(或 ...

  3. 【BZOJ4298】[ONTAK2015]Bajtocja

    [BZOJ4298][ONTAK2015]Bajtocja Description 给定d张无向图,每张图都有n个点.一开始,在任何一张图中都没有任何边.接下来有m次操作,每次操作会给出a,b,k,意 ...

  4. docker学习笔记(二)-dockerfile docker仓库

    dckerfile2这样写才对,不然打印的是hello $name 例子 登陆https://hub.docker.com 上面是提交到公共仓库 创建本地私有仓库 开启另外一个虚机,将重新构建上传镜像 ...

  5. Nginx+Keepalived双机热备

    一.Keepalived Keepalived是保证集群高可用的服务软件.网络中优先级高的节点为master负责响应VIP的ARP包,将VIP和MAC地址映射关系告诉网络内其他主机,还会以多播的形式向 ...

  6. 给定一个正整数n,返回从1到n构成的所有的BST

    public class C3 { public static void main(String[] args) { ArrayList<TreeNode> res = generateT ...

  7. Python socket套接字简单例子

  8. 005_python对整数的拼接

    一. (1)需要把整数组成的列表或整数字符串混合的列表拼接成字符串,实现如下: arr=[1,2,3,4,"5"] print ','.join(map(str,arr)) pri ...

  9. AJAX请求返回HTTP 400 错误 - 请求无效 (Bad request)

    在ajax请求后台数据时有时会报HTTP400错误-请求无效(Badrequest);出现这个请求无效报错说明请求没有进入到后台服务里: 原因: 1)前端提交数据的字段名称或者是字段类型和后台的实体类 ...

  10. 性能调优9:根据WaitType诊断性能

    SQL Server数据库接收到查询请求,从生成计划到执行计划的过程,等待次数和等待时间在一定程度上揭示了系统性能的压力,如果资源严重不足,就会成为性能的瓶颈.因此,对等待的监控非常有助于对系统性能进 ...