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