Java后端WebSocket的Tomcat实现

 

原文:https://www.cnblogs.com/xdp-gacl/p/5193279.html

一.WebSocket简单介绍

  随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。

  我们知道,传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应 用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)Comet技术。其实后者本质上也是一种轮询,只不过有所改进。

  轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。

  Comet技术又可以分为长轮询流技术长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。

  这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。

  伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。WebSocket的工作流程是这 样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小 了很多。本文不详细地介绍WebSocket规范,主要介绍下WebSocket在Java Web中的实现。

  JavaEE 7中出了JSR-356:Java API for WebSocket规范。不少Web容器,如Tomcat,Nginx,Jetty等都支持WebSocket。Tomcat从7.0.27开始支持 WebSocket,从7.0.47开始支持JSR-356,下面的Demo代码也是需要部署在Tomcat7.0.47以上的版本才能运行。

二.WebSocket示例

2.1.新建JavaWeb测试项目

  

  在pom.xml中添加Jar包依赖

复制代码
1 <dependency>
2         <groupId>javax</groupId> 3 <artifactId>javaee-api</artifactId> 4 <version>7.0</version> 5 <scope>provided</scope> 6 </dependency>
复制代码

  客户端(Web主页)代码:

复制代码
 1 <%@ page language="java" pageEncoding="UTF-8" %>  2 <!DOCTYPE html>  3 <html>  4 <head>  5 <title>Java后端WebSocket的Tomcat实现</title>  6 </head>  7 <body>  8 Welcome<br/><input id="text" type="text"/>  9 <button onclick="send()">发送消息</button> 10 <hr/> 11 <button onclick="closeWebSocket()">关闭WebSocket连接</button> 12 <hr/> 13 <div id="message"></div> 14 </body> 15 16 <script type="text/javascript"> 17 var websocket = null; 18 //判断当前浏览器是否支持WebSocket 19 if ('WebSocket' in window) { 20  websocket = new WebSocket("ws://localhost:8080/项目名/websocket"); 21  } 22 else { 23  alert('当前浏览器 Not support websocket') 24  } 25 26 //连接发生错误的回调方法 27  websocket.onerror = function () { 28  setMessageInnerHTML("WebSocket连接发生错误"); 29  }; 30 31 //连接成功建立的回调方法 32  websocket.onopen = function () { 33  setMessageInnerHTML("WebSocket连接成功"); 34  } 35 36 //接收到消息的回调方法 37  websocket.onmessage = function (event) { 38  setMessageInnerHTML(event.data); 39  } 40 41 //连接关闭的回调方法 42  websocket.onclose = function () { 43  setMessageInnerHTML("WebSocket连接关闭"); 44  } 45 46 //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 47 window.onbeforeunload = function () { 48 closeWebSocket(); 49 } 50 51 //将消息显示在网页上 52 function setMessageInnerHTML(innerHTML) { 53 document.getElementById('message').innerHTML += innerHTML + '<br/>'; 54 } 55 56 //关闭WebSocket连接 57 function closeWebSocket() { 58 websocket.close(); 59 } 60 61 //发送消息 62 function send() { 63 var message = document.getElementById('text').value; 64 websocket.send(message); 65 } 66 </script> 67 </html>
复制代码

  Java Web后端代码

复制代码
 1 package me.gacl.websocket;
 2 
 3 import java.io.IOException;  4 import java.util.concurrent.CopyOnWriteArraySet;  5  6 import javax.websocket.*;  7 import javax.websocket.server.ServerEndpoint;  8  9 /** 10  * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, 11  * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 12 */ 13 @ServerEndpoint("/websocket") 14 public class WebSocketTest { 15 //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 16 private static int onlineCount = 0; 17 18 //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 19 private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>(); 20 21 //与某个客户端的连接会话,需要通过它来给客户端发送数据 22 private Session session; 23 24 /** 25  * 连接建立成功调用的方法 26  * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 27 */ 28  @OnOpen 29 public void onOpen(Session session){ 30 this.session = session; 31 webSocketSet.add(this); //加入set中 32 addOnlineCount(); //在线数加1 33 System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); 34  } 35 36 /** 37  * 连接关闭调用的方法 38 */ 39  @OnClose 40 public void onClose(){ 41 webSocketSet.remove(this); //从set中删除 42 subOnlineCount(); //在线数减1 43 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); 44  } 45 46 /** 47  * 收到客户端消息后调用的方法 48  * @param message 客户端发送过来的消息 49  * @param session 可选的参数 50 */ 51  @OnMessage 52 public void onMessage(String message, Session session) { 53 System.out.println("来自客户端的消息:" + message); 54 //群发消息 55 for(WebSocketTest item: webSocketSet){ 56 try { 57  item.sendMessage(message); 58 } catch (IOException e) { 59  e.printStackTrace(); 60 continue; 61  } 62  } 63  } 64 65 /** 66  * 发生错误时调用 67  * @param session 68  * @param error 69 */ 70  @OnError 71 public void onError(Session session, Throwable error){ 72 System.out.println("发生错误"); 73  error.printStackTrace(); 74  } 75 76 /** 77  * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 78  * @param message 79  * @throws IOException 80 */ 81 public void sendMessage(String message) throws IOException{ 82 this.session.getBasicRemote().sendText(message); 83 //this.session.getAsyncRemote().sendText(message); 84 } 85 86 public static synchronized int getOnlineCount() { 87 return onlineCount; 88 } 89 90 public static synchronized void addOnlineCount() { 91 WebSocketTest.onlineCount++; 92 } 93 94 public static synchronized void subOnlineCount() { 95 WebSocketTest.onlineCount--; 96 } 97 }
复制代码

 1.2.运行效果

  同时打开Google浏览器和火狐浏览器进行多客户端模拟测试,运行效果如下:

  

  该Demo在Jdk1.7+Tomcat7.0.65下环境测试过,示例项目代码下载

  本篇博客的大部分内容转载自http://blog.chenzuhuang.com/archive/28.html,然后在此基础上进行完善,在此对作者表示感谢.

 

注意:如果按照上面一通操作后,还是页面报错 说链接不上 websocket 请参考文章:

1:WebSocket与Tomcat兼容问题

2:web项目引用tomcat中的jar

转载于:https://www.cnblogs.com/libin6505/p/9707565.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/388405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

加速业务交付,从 GKE 上使用 Kubernetes 和 Istio 开始

原文来源于&#xff1a;谷歌云技术博客 许多企业机构正在把全部或部分 IT 业务迁移到云端&#xff0c;帮助企业更好的运营。不过这样的大规模迁移&#xff0c;在企业的实际操作中也有一定难度。不少企业保存在本地服务器的重要资源&#xff0c;并不支持直接迁移到云端。 另外&a…

knn 邻居数量k的选取_选择K个最近的邻居

knn 邻居数量k的选取Classification is more-or-less just a matter of figuring out to what available group something belongs.分类或多或少只是弄清楚某个事物所属的可用组的问题。 Is Old Town Road a rap song or a country song?Old Town Road是说唱歌曲还是乡村歌曲…

计算机网络中 子网掩码的算法,[网络天地]子网掩码快速算法(转载)

看到一篇很好的资料&#xff0c;大家分享有很多人肯定对设定子网掩码这个不熟悉&#xff0c;很头疼&#xff0c;那么我现在就告诉大家一个很容易算子网掩码的方法&#xff0c;帮助一下喜欢偷懒的人&#xff1a;)大家都应该知道2的0次方到10次方是多少把&#xff1f;也给大家说一…

EXTJS+JSP上传文件带进度条

需求来源是这样的&#xff1a;上传一个很大的excel文件到server&#xff0c; server会解析这个excel&#xff0c; 然后一条一条的插入到数据库&#xff0c;整个过程要耗费很长时间&#xff0c;因此当用户点击上传之后&#xff0c;需要显示一个进度条&#xff0c;并且能够根据后…

android Json详解

Json:一种轻量级的数据交换格式&#xff0c;具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案&#xff08;有点类似于正则表达式 &#xff0c;获得了当今大部分语言的支持&#xff09;&#xff0c;从而可以在不同平台间进行数据交换。JSON采用兼容性…

react实践

React 最佳实践一、 React 与 AJAXReact 只负责处理 View 这一层&#xff0c;它本身不涉及网络请求 /AJAX: 第一&#xff0c;用什么技术从服务端获取数据&#xff1b; 第二&#xff0c;获取到的数据应该放在 react 组件的什么位置。 事实上是有很多的&#xff1a;fetch()、fetc…

什么样的代码是好代码_什么是好代码?

什么样的代码是好代码编码最佳实践 (Coding Best-Practices) In the following section, I will introduce the topic at hand, giving you a sense of what this post will cover, and how each argument therein will be approached. Hopefully, this will help you decide w…

nginx比较apache

话说nginx在大压力的环境中比apache的表现要好&#xff0c;于是下载了一个来折腾一下。 下载并编译安装&#xff0c;我的编译过程有点特别&#xff1a; 1。去除调试信息&#xff0c;修改$nginx_setup_path/auto/cc/gcc这个文件&#xff0c;将 CFLAGS"$CFLAGS -g" …

计算机主板各模块复位,电脑主板复位电路工作原理分析

电源、时钟、复位是主板能正常工作的三大要素。主板在电源、时钟都正常后&#xff0c;复位系统发出复位信号&#xff0c;主板各个部件在收到复位信号后&#xff0c;同步进入初始化状态。如图7-11所示为复位电路的工作原理图&#xff0c;各个十板实现复位的电路不尽相同&#xf…

Docker制作dotnet core控制台程序镜像

(1)首先我们到某个目录下&#xff0c;然后在此目录下打开visual studio code. 2.编辑docker file文件如下: 3.使用dotnet new console创建控制台程序; 4.使用docker build -t daniel/console:dev .来进行打包; 5.启动并运行镜像; 6.我们可以看到打包完的镜像将近2G,因为我们使用…

【362】python 正则表达式

参考&#xff1a;正则表达式 - 廖雪峰 参考&#xff1a;Python3 正则表达式 - 菜鸟教程 参考&#xff1a;正则表达式 - 教程 re.match 尝试从字符串的起始位置匹配一个模式&#xff0c;如果不是起始位置匹配成功的话&#xff0c;match()就返回none。 re.search 扫描整个字符串并…

在Python中使用Twitter Rest API批量搜索和下载推文

数据挖掘 &#xff0c; 编程 (Data Mining, Programming) Getting Twitter data获取Twitter数据 Let’s use the Tweepy package in python instead of handling the Twitter API directly. The two things we will do with the package are, authorize ourselves to use the …

第一套数字电子计算机,计算机试题第一套

《计算机试题第一套》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《计算机试题第一套(5页珍藏版)》请在人人文库网上搜索。1、计算机试题第一套1、计算机之所以能自动运算,就是由于采用了工作原理。A、布尔逻辑。B 储存程序。C、数字电路。D,集成电路答案选B2、“长…

Windows7 + Nginx + Memcached + Tomcat 集群 session 共享

一&#xff0c;环境说明 操作系统是Windows7家庭版&#xff08;有点不专业哦&#xff0c;呵呵&#xff01;&#xff09;&#xff0c;JDK是1.6的版本&#xff0c; Tomcat是apache-tomcat-6.0.35-windows-x86&#xff0c;下载链接&#xff1a;http://tomcat.apache.org/ Nginx…

git 版本控制(一)

新建代码库repository 1、在当前目录新建一个git代码库 git init git init projectname 2、下载一个项目&#xff0c;如果已经有了远端的代码&#xff0c;则可以使用clone下载 git clone url 增加/删除/改名文件 1、添加指定文件到暂存区 git add filename 2、添加指定目录到暂…

rollup学习小记

周末在家重构网关的Npm包&#xff0c;用到了rollup&#xff0c;记下笔记 rollup适合库library的开发&#xff0c;而webpack适合应用程序的开发。 rollup也支持tree-shaking&#xff0c;自带的功能。 package.json 也具有 module 字段&#xff0c;像 Rollup 和 webpack 2 这样的…

大数据 vr csdn_VR中的数据可视化如何革命化科学

大数据 vr csdnAstronomy has become a big data discipline, and the ever growing databases in modern astronomy pose many new challenges for analysts. Scientists are more frequently turning to artificial intelligence and machine learning algorithms to analyze…

object-c 日志

printf和NSlog区别 NSLog会自动加上换行符&#xff0c;不需要自己添加换行符&#xff0c;NSLog会加上时间和进程信息&#xff0c;而printf仅将输入的内容输出不会添加任何额外的东西。两者的输入类型也是有区别的NSLog期待NSString*&#xff0c;而printf期待const char *。最本…

计算机真正管理的文件名是什么,计算机题,请大家多多帮忙,谢谢

4、在资源管理器中&#xff0c;若想显示文件名、文件大小和文件类型&#xff0c;应采用什么显示方式。( )A、小图标显示 B、列表显示 C、详细资料显示 D、缩略图显示5、在EXCEL中&#xff0c;可以依据不同要求来提取和汇总数据&#xff0c;4、在资源管理器中&#xff0c;若想显…

小a的排列

链接&#xff1a;https://ac.nowcoder.com/acm/contest/317/G来源&#xff1a;牛客网小a有一个长度为nn的排列。定义一段区间是"萌"的&#xff0c;当且仅当把区间中各个数排序后相邻元素的差为11 现在他想知道包含数x,yx,y的长度最小的"萌"区间的左右端点 …