WebSocket是在HTML5中引入的浏览器与服务端的通讯协议,能够类比HTTP。
能够在支持HTML5的浏览器版本中使用WebSocket进行数据通讯,常见的案例是使用WebSocket进行实时数据刷新。
关于WebSocket详细的功能性描述,详见:https://zh.wikipedia.org/wiki/WebSocket。
在这里主要说明在tomcat中如何编写WebSocket服务端程序。html
从tomcat7开始支持WebSocket,可是从tomcat8以后使用了关于WebSocket的注解,就得WebSocket API废弃不用。
因此,须要分别按tomcat7和tomcat8+来讲明如何使用WebSocket。java
<!-- 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程序是同样的。nginx
/** * 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便可。web
特别注意: tomcat7中的WebSocket API在tomcat8以后就已经废弃,要根据实际的运行环境选择对应实现。apache
在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 Proxyapi