一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Java中Websocket使用實例解讀 – 碼農網

 spzproot 2016-04-20

介紹

現(xiàn)在很多網站為了實現(xiàn)即時通訊,所用的技術都是輪詢(polling)。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發(fā)出HTTP request,然后由服務器返回最新的數(shù)據給客服端的瀏覽器。

這種傳統(tǒng)的HTTP request 的模式帶來很明顯的缺點 – 瀏覽器需要不斷的向服務器發(fā)出請求,然而HTTP request 的header是非常長的,里面包含的數(shù)據可能只是一個很小的值,這樣會占用很多的帶寬。

而最比較新的技術去做輪詢的效果是comet – 用了AJAX。但這種技術雖然可達到全雙工通信,但依然需要發(fā)出請求。

在 WebSocket API,瀏覽器和服務器只需要要做一個握手的動作,然后,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據互相傳送。

運行環(huán)境:

客戶端

實現(xiàn)了websocket的瀏覽器

ChromeSupported in version 4+
FirefoxSupported in version 4+
Internet ExplorerSupported in version 10+
OperaSupported in version 10+
SafariSupported in version 5+

服務端

依賴

Tomcat 7.0.47以上 + J2EE7

    org.apache.tomcat      tomcat-websocket-api      7.0.47      provided          javax      javaee-api      7.0      provided  

注意:早前業(yè)界沒有統(tǒng)一的標準,各服務器都有各自的實現(xiàn),現(xiàn)在J2EE7的JSR356已經定義了統(tǒng)一的標準,請盡量使用支持最新通用標準的服務器。

詳見:
http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html
http://jinnianshilongnian./blog/1909962

我是用的Tomcat 7.0.57 + Java7
必須是Tomcat 7.0.47以上
詳見:http://www./news/28414

ps:最早我們是用的Tomcat 7自帶的實現(xiàn),后來要升級Tomcat 8,結果原來的實現(xiàn)方式在Tomcat 8不支持了,就只好切換到支持Websocket 1.0版本的Tomcat了。

主流的java web服務器都有支持JSR365標準的版本了,請自行Google。

用nginx做反向代理的需要注意啦,socket請求需要做特殊配置的,切記!

Tomcat的處理方式建議修改為NIO的方式,同時修改連接數(shù)到合適的參數(shù),請自行Google!

服務端不需要在web.xml中做額外的配置,Tomcat啟動后就可以直接連接了。

實現(xiàn)

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的標準 *         切忌直接在該連接處理類中加入業(yè)務處理代碼 * 作者:liuxing(2014-11-14 04:20) *///relationId和userCode是我的業(yè)務標識參數(shù),websocket.ws是連接的路徑,可以自行定義@ServerEndpoint('/websocket.ws/{relationId}/{userCode}')public class WebsocketEndPoint {    private static Log log = LogFactory.getLog(WebsocketEndPoint.class);    /**     * 打開連接時觸發(fā)     * @param relationId     * @param userCode     * @param session     */    @OnOpen    public 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);    }    /**     * 收到客戶端消息時觸發(fā)     * @param relationId     * @param userCode     * @param message     * @return     */    @OnMessage    public String onMessage(@PathParam('relationId') String relationId,                            @PathParam('userCode') int userCode,                            String message) {        return 'Got your message (' + message + ').Thanks !';    }    /**     * 異常時觸發(fā)     * @param relationId     * @param userCode     * @param session     */    @OnError    public 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);    }    /**     * 關閉連接時觸發(fā)     * @param relationId     * @param userCode     * @param session     */    @OnClose    public 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和連接

這個是我業(yè)務的需要,我的業(yè)務是服務器有對應動作觸發(fā)時,推送數(shù)據到客戶端,沒有接收客戶端數(shù)據的操作。

import javax.websocket.Session;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/** * 功能說明:用來存儲業(yè)務定義的sessionId和連接的對應關系 *          利用業(yè)務邏輯中組裝的sessionId獲取有效連接后進行后續(xù)操作 * 作者:liuxing(2014-12-26 02:32) */public class SessionUtils {    public static Map 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;    }}

推送數(shù)據到客戶端

在其他業(yè)務方法中調用

/** * 將數(shù)據傳回客戶端 * 異步的方式 * @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');    }}

我是使用異步的方法推送數(shù)據,還有同步的方法

詳見: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實現(xiàn)一個websocket的客戶端

依賴:

    org.java-websocket    Java-WebSocket    1.3.0

代碼:

import java.io.IOException;  import javax.websocket.ClientEndpoint;  import javax.websocket.OnError;  import javax.websocket.OnMessage;  import javax.websocket.OnOpen;  import javax.websocket.Session;  @ClientEndpoint  public class MyClient {      @OnOpen      public void onOpen(Session session) {          System.out.println('Connected to endpoint: ' + session.getBasicRemote());          try {              session.getBasicRemote().sendText('Hello');          } catch (IOException ex) {          }      }      @OnMessage      public void onMessage(String message) {          System.out.println(message);      }      @OnError      public 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-01

最后

為了統(tǒng)一的操作體驗,對于一些不支持websocket的瀏覽器,請使用socketjs技術做客戶端開發(fā)。

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    偷拍偷窥女厕一区二区视频| 午夜资源在线观看免费高清| 特黄大片性高水多欧美一级 | 欧美人禽色视频免费看| 麻豆视传媒短视频免费观看| 欧美日韩视频中文字幕| 经典欧美熟女激情综合网| 久久福利视频视频一区二区| 午夜视频成人在线免费| 亚洲精品中文字幕一二三| 99久久无色码中文字幕免费| 黄色国产一区二区三区| 欧美日本道一区二区三区| 偷拍洗澡一区二区三区| 欧美久久一区二区精品| 欧美韩日在线观看一区| 玩弄人妻少妇一区二区桃花| 午夜精品国产一区在线观看| 日韩综合国产欧美一区| 麻豆剧果冻传媒一二三区| 亚洲美女国产精品久久| 欧美成人免费夜夜黄啪啪 | 国产又粗又长又大的视频| 亚洲欧洲一区二区中文字幕| 色哟哟哟在线观看视频| 午夜亚洲少妇福利诱惑| 初尝人妻少妇中文字幕在线| 五月激情婷婷丁香六月网| 欧美日本精品视频在线观看| 99久久精品一区二区国产| 在线观看免费无遮挡大尺度视频| 少妇人妻一级片一区二区三区| 国产一区二区三区精品免费| 国产成人午夜av一区二区| 国产精品推荐在线一区| 五月婷婷六月丁香在线观看| 日韩高清中文字幕亚洲| 国产香蕉国产精品偷在线观看| 国产综合欧美日韩在线精品 | 在线九月婷婷丁香伊人| 亚洲专区中文字幕视频|