Java Websocket实例
2019獨角獸企業重金招聘Python工程師標準>>>
介紹
現很多網站為了實現即時通訊,所用的技術都是輪詢(polling)。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP request,然后由服務器返回最新的數據給客服端的瀏覽器。這種傳統的HTTP request 的模式帶來很明顯的缺點 – 瀏覽器需要不斷的向服務器發出請求,然而HTTP request 的header是非常長的,里面包含的數據可能只是一個很小的值,這樣會占用很多的帶寬。
而最比較新的技術去做輪詢的效果是Comet – 用了AJAX。但這種技術雖然可達到全雙工通信,但依然需要發出請求。
在 WebSocket API,瀏覽器和服務器只需要要做一個握手的動作,然后,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。
依賴:
Tomcat 7 或者?J2EE7
<dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-websocket-api</artifactId> <version>7.0.47</version> <scope>provided</scope> </dependency><dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency>注意:早前業界沒有統一的標準,各服務器都有各自的實現,現在J2EE7的JSR356已經定義了統一的標準,請盡量使用支持最新通用標準的服務器。
詳見:http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html
? ? ? ? ? ?http://jinnianshilongnian.iteye.com/blog/1909962
?
我是用的Tomcat 7.0.57 + Java7
必須是Tomcat 7.0.47以上
詳見:http://www.iteye.com/news/28414
?
ps:最早我們是用的Tomcat 7自帶的實現,后來要升級Tomcat 8,結果原來的實現方式在Tomcat 8不支持了,就只好切換到支持Websocket 1.0版本的Tomcat了。
?
主流的java web服務器都有支持JSR365標準的版本了,請自行Google。?
?
用nginx做反向代理的需要注意啦,socket請求需要做特殊配置的,切記!
?
Tomcat的處理方式建議修改為NIO的方式,同時修改連接數到合適的參數,請自行Google!
?
服務端
服務端不需要在web.xml中做額外的配置,Tomcat啟動后就可以直接連接了。
?
import?com.dooioo.websocket.utils.SessionUtils; import?org.apache.commons.logging.Log; import?org.apache.commons.logging.LogFactory;import?javax.websocket.*; import?javax.websocket.server.PathParam; import?javax.websocket.server.ServerEndpoint;/***?功能說明:websocket處理類,?使用J2EE7的標準*?切忌直接在該連接處理類中加入業務處理代碼*?作者:liuxing(2014-11-14?04:20) */ //relationId和userCode是我的業務標識參數,websocket.ws是連接的路徑,可以自行定義 @ServerEndpoint("/websocket.ws/{relationId}/{userCode}") public?class?WebsocketEndPoint?{private?static?Log?log?=?LogFactory.getLog(WebsocketEndPoint.class);/***?打開連接時觸發*?@param?relationId*?@param?userCode*?@param?session */ @OnOpenpublic?void?onOpen(@PathParam("relationId")?String?relationId,@PathParam("userCode")?int?userCode,Session?session){log.info("Websocket?Start?Connecting:"+?SessionUtils.getKey(relationId,?userCode));SessionUtils.put(relationId,?userCode,?session); }/***?收到客戶端消息時觸發*?@param?relationId*?@param?userCode*?@param?message*?@return */ @OnMessagepublic?String?onMessage(@PathParam("relationId")?String?relationId,@PathParam("userCode")?int?userCode,String?message)?{return"Got?your?message?("+?message?+").Thanks?!"; }/***?異常時觸發*?@param?relationId*?@param?userCode*?@param?session */ @OnErrorpublic?void?onError(@PathParam("relationId")?String?relationId,@PathParam("userCode")?int?userCode,Throwable?throwable,Session?session)?{log.info("Websocket?Connection?Exception:"+?SessionUtils.getKey(relationId,?userCode));log.info(throwable.getMessage(),?throwable);SessionUtils.remove(relationId,?userCode); }/***?關閉連接時觸發*?@param?relationId*?@param?userCode*?@param?session */ @OnClosepublic?void?onClose(@PathParam("relationId")?String?relationId,@PathParam("userCode")?int?userCode,Session?session)?{log.info("Websocket?Close?Connection:"+?SessionUtils.getKey(relationId,?userCode));SessionUtils.remove(relationId,?userCode); }}??
?
工具類用來存儲唯一key和連接
這個是我業務的需要,我的業務是服務器有對應動作觸發時,推送數據到客戶端,沒有接收客戶端數據的操作。
?
import?javax.websocket.Session; import?java.util.Map; import?java.util.concurrent.ConcurrentHashMap;/***?功能說明:用來存儲業務定義的sessionId和連接的對應關系*?利用業務邏輯中組裝的sessionId獲取有效連接后進行后續操作*?作者:liuxing(2014-12-26?02:32) */ public?class?SessionUtils?{public?static?Map<String,?Session>?clients?=?new?ConcurrentHashMap<>();public?static?void?put(String?relationId,?int?userCode,?Session?session){clients.put(getKey(relationId,?userCode),?session); }public?static?Session?get(String?relationId,?int?userCode){return?clients.get(getKey(relationId,?userCode)); }public?static?void?remove(String?relationId,?int?userCode){clients.remove(getKey(relationId,?userCode)); }/***?判斷是否有連接*?@param?relationId*?@param?userCode*?@return */public?static?boolean?hasConnection(String?relationId,?int?userCode)?{return?clients.containsKey(getKey(relationId,?userCode)); }/***?組裝唯一識別的key*?@param?relationId*?@param?userCode*?@return */public?static?String?getKey(String?relationId,?int?userCode)?{return?relationId?+"_"+?userCode; }}?
?
推送數據到客戶端
?
在其他業務方法中調用
?
/***?將數據傳回客戶端*?異步的方式*?@param?relationId*?@param?userCode*?@param?message */public?void?broadcast(String?relationId,?int?userCode,?String?message)?{if?(TelSocketSessionUtils.hasConnection(relationId,?userCode))?{TelSocketSessionUtils.get(relationId,?userCode).getAsyncRemote().sendText(message);}?else?{throw?new?NullPointerException(TelSocketSessionUtils.getKey(relationId,?userCode)?+"Connection?does?not?exist"); }}?
我是使用異步的方法推送數據,還有同步的方法
詳見:http://docs.oracle.com/javaee/7/api/javax/websocket/Session.html
?
客戶端
var?webSocket?=?null; var?tryTime?=?0; $(function?()?{ initSocket();window.onbeforeunload?=?function?()?{ //離開頁面時的其他操作 }; });/***?初始化websocket,建立連接 */ function?initSocket()?{if?(!window.WebSocket)?{ alert("您的瀏覽器不支持websocket!");return?false; }webSocket?=?new?WebSocket("ws://127.0.0.1:8080/websocket.ws/"+?relationId?+"/"+?userCode);//?收到服務端消息webSocket.onmessage?=?function?(msg)?{ console.log(msg); };//?異常webSocket.onerror?=?function?(event)?{ console.log(event); };//?建立連接webSocket.onopen?=?function?(event)?{ console.log(event); };//?斷線重連webSocket.onclose?=?function?()?{//?重試10次,每次之間間隔10秒if?(tryTime?<?10)?{setTimeout(function?()?{webSocket?=?null; tryTime++; initSocket();},?500);}?else?{tryTime?=?0; } };}?
其他調試工具
Java實現一個websocket的客戶端
?
<dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.3.0</version> </dependency>?
import?java.io.IOException;?import?javax.websocket.ClientEndpoint;?import?javax.websocket.OnError;?import?javax.websocket.OnMessage;?import?javax.websocket.OnOpen;?import?javax.websocket.Session;?@ClientEndpointpublic?class?MyClient?{? @OnOpenpublic?void?onOpen(Session?session)?{?System.out.println("Connected?to?endpoint:"+?session.getBasicRemote());?try?{? session.getBasicRemote().sendText("Hello");}?catch?(IOException?ex)?{? } }@OnMessagepublic?void?onMessage(String?message)?{? System.out.println(message); }@OnErrorpublic?void?onError(Throwable?t)?{? t.printStackTrace(); } }?
import?java.io.BufferedReader;?import?java.io.IOException;?import?java.io.InputStreamReader;?import?java.net.URI;?import?javax.websocket.ContainerProvider;?import?javax.websocket.DeploymentException;?import?javax.websocket.Session;?import?javax.websocket.WebSocketContainer;?public?class?MyClientApp?{?public?Session?session;?protected?void?start()? {WebSocketContainer?container?=?ContainerProvider.getWebSocketContainer();?String?uri?="ws://127.0.0.1:8080/websocket.ws/relationId/12345";?System.out.println("Connecting?to"+?uri);?try?{?session?=?container.connectToServer(MyClient.class,?URI.create(uri));?}?catch?(DeploymentException?e)?{? e.printStackTrace();}?catch?(IOException?e)?{? e.printStackTrace(); }}public?static?void?main(String?args[]){?MyClientApp?client?=?new?MyClientApp();? client.start();BufferedReader?br?=?new?BufferedReader(new?InputStreamReader(System.in));?String?input?="";?try?{? do{input?=?br.readLine();? if(!input.equals("exit")) client.session.getBasicRemote().sendText(input);}while(!input.equals("exit"));}?catch?(IOException?e)?{?//?TODO?Auto-generated?catch?block? e.printStackTrace(); } } }?
?
Chrome安裝一個websocket模擬客戶端
?
?
?
最后
為了統一的操作體驗,對于一些不支持websocket的瀏覽器,請使用socketjs技術做客戶端開發。
轉載于:https://my.oschina.net/sphl520/blog/398382
總結
以上是生活随笔為你收集整理的Java Websocket实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 编码规范11(安全规约)
- 下一篇: Dos下命令运行带有包名的Java类