WebSocket是在HTML5中引入的浏览器与服务端的通信协议,可以类比HTTP。

可以在支持HTML5的浏览器版本中使用WebSocket进行数据通信,常见的案例是使用WebSocket进行实时数据刷新。

关于WebSocket详细的功能性描述,详见:https://zh.wikipedia.org/wiki/WebSocket。

在这里主要说明在tomcat中如何编写WebSocket服务端程序。

从tomcat7开始支持WebSocket,但是从tomcat8之后使用了关于WebSocket的注解,就得WebSocket API废弃不用。

所以,需要分别按tomcat7和tomcat8+来说明如何使用WebSocket。

tomcat7使用websocket

<!-- tomcat7中实现websocket: 定义servlet -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>7.0.39</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-coyote</artifactId>
<version>7.0.39</version>
<scope>provided</scope>
</dependency>

在tomcat7中实现WebSocket服务端,与编写一个Servlet程序是一样的。

/**
* tomcat7中实现websocket servlet
* @desc org.chench.test.web.websocket.WsServlet
* @author chench9@lenovo.com
* @date 2017年10月9日
*/
public class WsChatServlet extends WebSocketServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(WsChatServlet.class); private List<MyMessageInBound> milist = new ArrayList<MyMessageInBound>(); // 客户端列表 /**
* 对应每一个客户端连接都创建不同的对象处理
*/
@Override
protected StreamInbound createWebSocketInbound(String arg0, HttpServletRequest arg1) {
return new MyMessageInBound();
} /**
* 处理客户端WebSocket连接请求
* @desc org.chench.test.web.websocket.MyMessageInBound
* @author chench9@lenovo.com
* @date 2017年10月9日
*/
private class MyMessageInBound extends MessageInbound {
private WsOutbound wso = null; @Override
protected void onBinaryMessage(ByteBuffer message) throws IOException {
if(logger.isDebugEnabled()) {
logger.debug("onBinaryMessage");
}
// do nothing
} @Override
protected void onTextMessage(CharBuffer message) throws IOException {
if(logger.isDebugEnabled()) {
logger.debug("onTextMessage");
} for(MyMessageInBound mmib : milist) {
CharBuffer buffer = CharBuffer.wrap(message);
mmib.getWsOutbound().writeTextMessage(buffer);
mmib.getWsOutbound().flush();
}
} @Override
protected void onOpen(WsOutbound outbound) {
if(logger.isDebugEnabled()) {
logger.debug("websocket client connection add");
}
this.wso = outbound;
milist.add(this);
try {
outbound.writeTextMessage(CharBuffer.wrap("Hello"));
} catch (IOException e) {
e.printStackTrace();
} logger.info("websocket client list size: {}", milist.size()); } @Override
protected void onClose(int status) {
if(logger.isDebugEnabled()) {
logger.debug("websocket client closed! {}", this.wso.toString());
}
milist.remove(this);
}
}
}

最后在web.xml文件中配置该Servlet即可。

tomcat8+使用websocket

特别注意: tomcat7中的WebSocket API在tomcat8之后就已经废弃,要根据实际的运行环境选择对应实现。

在tomcat8之后,使用了新的WebSocket API。具体来说,是通过注解方式编写WebSocket服务端。

<!-- 在tomcat8中实现websocket: 使用注解 -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-websocket-api</artifactId>
<version>8.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-websocket</artifactId>
<version>8.0.1</version>
</dependency>
/**
* 在tomcat8+中实现websocket,通过注解
* @desc org.chench.test.web.websocket.WsChatAnnotation
* @author chench9@lenovo.com
* @date 2017年10月9日
*/
@ServerEndpoint(value="/ws/chatAnnotation")
public class WsChatAnnotation {
private static final Logger logger = LoggerFactory.getLogger(WsChatAnnotation.class); private static final AtomicInteger counter = new AtomicInteger(0); // 客户端计数器
private static final Set<WsChatAnnotation> connections = new CopyOnWriteArraySet<WsChatAnnotation>(); // 客户端websocket连接
private Session session = null;
private Integer number = 0; // 客户端编号 public WsChatAnnotation() {
number = counter.incrementAndGet();
} /**
* 客户端建立websocket连接
* @param session
*/
@OnOpen
public void start(Session session) {
logger.info("on open");
this.session = session;
connections.add(this);
try {
session.getBasicRemote().sendText(new StringBuffer().append("Hello: ").append(number).toString());
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 客户端断开websocket连接
*/
@OnClose
public void close() {
logger.info("session close");
try {
this.session.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
connections.remove(this);
}
} /**
* 接收客户端发送的消息
* @param message
*/
@OnMessage
public void message(String message) {
logger.info("message");
logger.info("message: {}", message); for(WsChatAnnotation client : connections) {
synchronized (client) {
try {
client.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// end for
} @OnError
public void error(Throwable t) {
logger.error("client: {} error", number, t);
}
}

【参考】

http://www.cnblogs.com/xdp-gacl/p/5193279.html Java后端WebSocket的Tomcat实现

http://blog.fens.me/java-websocket-intro/ Java现实WebSocket

http://tomcat.apache.org/tomcat-7.0-doc/web-socket-howto.html tomcat7 web socket

http://tomcat.apache.org/tomcat-8.0-doc/web-socket-howto.html tomcat8 web socket

https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket WebSocket对象api

https://www.zhihu.com/question/20215561 WebSocket 是什么原理?为什么可以实现持久连接?

https://www.nginx.com/blog/websocket-nginx/ NGINX as a WebSocket Proxy

解决浏览器跨域限制方案之WebSocket的更多相关文章

  1. 解决浏览器跨域限制方案之CORS

    一.什么是CORS CORS是解决浏览器跨域限制的W3C标准,详见:https://www.w3.org/TR/cors/. 根据CORS标准的定义,在浏览器中访问跨域资源时,需要做如下实现: 服务端 ...

  2. 解决浏览器跨域限制方案之JSONP

    一.什么是JSONP JSONP即:JSON with Padding,是一种解决因浏览器跨域限制不允许访问跨域资源的方法. JSONP是一个非官方的协议,它允许在服务器端返回javascript标签 ...

  3. 配置nginx反向代理服务器,解决浏览器跨域调用接口的限制问题

    配置nginx反向代理服务器,解决浏览器跨域调用接口的限制问题 - 大venn的博客 - CSDN博客https://blog.csdn.net/u011135260/article/details/ ...

  4. node端代理浏览器路由 解决浏览器跨域问题

    var _ = require('lodash'); var request = require("request"); /* @LM 2017-02-16 node端代理浏览器路 ...

  5. c#解决浏览器跨域问题

    1.浏览器为什么不能跨域? 浏览器有一个基本的安全策略--同源策略.为保证用户的信息安全,它对不同源的文档或脚本对当前文档的读写操作做了限制.域名,子域名,端口号或协议不同都属于不同源,当脚本被认为是 ...

  6. nginx解决浏览器跨域问题

    1.跨域问题 浏览器出于安全方面的考虑,只允许与本域下的接口交互.不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源. 例如访问www.test1.com 页面, 返回的文件中需要ajax向 ...

  7. elk 解决浏览器跨域问题

    1.执行命令: docker pull sebp/elk 将镜像pull到本地来: 2.执行命令: docker run -p 5601:5601 -p 9200:9200 -p 5044:5044 ...

  8. [1.6W字]浏览器跨域请求的原理, 以及解决方法(可以纯前端实现) #flight.Archives011

    Title/ 浏览器跨域(CrossOrigin)请求的原理, 以及解决方案详细指南 #flight.Archives011 序: 最近看到又有一波新的创作活动了, 官方给出的话题中有一个" ...

  9. 说说JSON和JSONP,浅析JSONP解决AJAX跨域问题

    说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?这两个问题目前都有不同的解决方案,比如数据可以用自定义字符串或者用XML来描述,跨域可以通过服 ...

随机推荐

  1. android ViewStub简单介绍

    ViewStub是一种非常灵活的视图,主要用于布局资源的实时加载. ViewStub 的继承类关系如下: public final class ViewStubextends View java.la ...

  2. NOIP2013花匠(波动序列)

    波动序列的定义不用多说,下面给出波动序列的求法. #include<iostream> #include<cstdio> #define N 100002 using name ...

  3. 【Linux】linux正则表达式及通配符

    正则表达式就是用于匹配每行输入的一种模式,模式是指一串字符序列.拥有强大的字符搜索功能.也非常方便的搜索过滤出我们想要的内容. linux正则表达式分为基本正则表达式(Basic Regexp)和扩展 ...

  4. centos7添加并挂载新硬盘

    环境目标: 配置一台centos7,主硬盘40G装系统:副硬盘200G作为数据盘(格式:XFS)挂载到根目录:/data/ 说明:XFS是高性能文件系统,SGI为他们的 IRIX平台而设计: 自从20 ...

  5. Codeforces Round #508 (Div. 2) C D

    C: C - Gambling 给你两个数列  每一回合A可以选择从第一个序列里面选一个数或者清除第二个序列里面选一个数 同理B能从第二序列里面选数或者清除第一个序列里面一个数 然后 求A所选的数之和 ...

  6. Git多个SSH KEYS解决方案(含windows自动化、TortoiseGit、SourceTree等)

    工作过程中,经常会使用到多个git仓库,每个git仓库对应一个账号,可以理解为每个git仓库对应一个ssh key,因此我们需要管理多个ssh key.   一.快速创建ssh key   1. 创建 ...

  7. bzoj1497 最大获利(最大权闭合子图)

    题目链接 思路 对于每个中转站向\(T\)连一条权值为建这个中转站代价的边.割掉这条边表示会建这个中转站. 对于每个人向他的两个中转站连一条权值为\(INF\)的边.然后从\(S\)向这个人连一条权值 ...

  8. java利用线程池处理集合

    java利用线程池处理集合 2018年07月23日 17:21:19 衍夏成歌 阅读数:866   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/s ...

  9. Windows7安装程序无法定位现有系统分区,也无法创建新的系统分区

    解决Windows7.Windows8系统安装时“安装程序无法定位现有系统分区,也无法创建新的系统分区”提示. 方法一 把Windows7镜像发在你电脑的非系统盘的其他硬盘上. 重启机器,通过U盘启动 ...

  10. google chrome 浏览器书签丢失问题

    在一次新打开标签页时,电脑卡死,强制重启后打开google chrome 浏览器,发现历史什么的都在,但书签栏全部丢失了 找到 系统盘:\Users\用户名\AppData\Local\Google\ ...