長連接 Socket.IO


概念

說到長連接,對應的就是短連接了。下面先說明一下長連接和短連接的區別:

短連接與長連接

通俗來講,瀏覽器和服務器每進行一次通信,就建立一次連接,任務結束就中斷連接,即短連接。相反地,假如通信結束(如完成了某個HTML文件的信息獲取)后保持連接則為長連接。在HTTP/1.0中,默認使用短連接。從HTTP/1.1起,默認使用長連接,這樣做的優點是顯而易見的,一個網頁的加載可能需要HTML文件和多個CSS或者JS,假如每獲取一個靜態文件都建立一次連接,那么就太浪費時間了,而在保持連接的情況下,繼續GET即可。
對於頻繁請求資源的客戶來說,較適用長連接。但連接數最好進行限制,防止建立太多連接拖累服務端。一般瀏覽器對一個網站的連接是有限制的幾個,所以網站會將資源部署在多個域名上以實現瀏覽器同時請求。
短/長連接應當在TCP連接的范疇中來討論。有人常說HTTP的短連接和長連接如何如何,但是HTTP只是一個應用層協議,又是無狀態的,最終實質性的保持連接還是得靠傳輸層,即TCP。

keep-alive

我們使用瀏覽器的開發者工具查看網絡請求和響應信息時經常在HTTP請求頭部看到Connection: keep-alive,一般的瀏覽器都會帶着個頭去請求數據,假如有特殊需求可以用Connection: close斷開。HTTP頭部的Connection也不一定就被客戶端或服務端老老實實地遵循,畢竟各有各的考慮,尤其是在HTTP/1.0這還只是個實驗性的功能,而在HTTP/1.1默認長連接於是沒有對長連接做特殊的規定。長連接也不能無限期地長,服務端有可能在頭部放Keep-Alive,其中timeout等於一個值來規定保持連接的秒數,還可以用max來規定多少次請求后斷開。如果沒有說明怎么斷開,主動發起四次握手也可以實現連接的斷開。
HTTP的keep-alive與TCP的keep-alive到底是什么關系? 答: TCP的keep alive是檢查當前TCP連接是否活着;HTTP的Keep-alive是要讓一個TCP連接活久點

Socket.IO

該項目是從JavaScript遷移過來的。demo項目地址: Android chat demo
在Android Studio里面引入Socket.IO,在build.gradle里面加入:
compile ('io.socket:socket.io-client:0.8.3') {
  // excluding org.json which is provided by Android
  exclude group: 'org.json', module: 'json'
}

使用Socket.IO

Socket.IO-client 基本上和JS版本有相同的API,你使用IO.socket()來初始化Socket。
socket = IO.socket("http://localhost");  // 創建Socket.IO長連接對象
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {

  @Override
  public void call(Object... args) {
    socket.emit("foo", "hi");
    socket.disconnect();
  }

}).on("event", new Emitter.Listener() {

  @Override
  public void call(Object... args) {}

}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

  @Override
  public void call(Object... args) {}

}); // 注冊事件監聽對象 各種Event
socket.connect();  // 連接socket

這個庫使用org.json來解析和組成JSON字符串。

// Sending an object
JSONObject obj = new JSONObject();
obj.put("hello", "server");
obj.put("binary", new byte[42]);
socket.emit("foo", obj);

// Receiving an object
socket.on("foo", new Emitter.Listener() {
  @Override
  public void call(Object... args) {
    JSONObject obj = (JSONObject)args[0];
  }
});

提供了如下的選項可以設置:

IO.Options opts = new IO.Options();
opts.forceNew = true;
opts.reconnection = false;
socket = IO.socket("http://localhost", opts);

你可以使用這些參數來配置選項。注:如果你不想重用緩存的socket實例來查詢參數變化時,你應該使用forceNew選項。如果你的程序想要登出一個用戶,再登錄一個新用戶的時候可以使用這種方式:

IO.Options opts = new IO.Options();
opts.forceNew = true;
opts.query = "auth_token=" + authToken;
Socket socket = IO.socket("http://localhost", opts);

你可以得到一個回調來確認服務器收到一個消息:

socket.emit("foo", "woot", new Ack() {
  @Override
  public void call(Object... args) {}
});

反過來,你也可以發送一個確認消息,告訴服務器你收到了一個消息:

// ack from client to server
socket.on("foo", new Emitter.Listener() {
  @Override
  public void call(Object... args) {
    Ack ack = (Ack) args[args.length - 1];
    ack.call();
  }
});

你能夠使用SSL(HTTPS、WSS)的設置:

// default settings for all sockets
IO.setDefaultSSLContext(mySSLContext);
IO.setDefaultHostnameVerifier(myHostnameVerifier);

// set as an option
opts = new IO.Options();
opts.sslContext = mySSLContext;
opts.hostnameVerifier = myHostnameVerifier;
socket = IO.socket("https://localhost", opts);

查詢更多Java文檔可以查看:

http://socketio.github.io/socket.io-client-java/apidocs/

使用Transports訪問Http頭:(不常用,一般用來設置Cookie參數)

// Called upon transport creation.
socket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() {
  @Override
  public void call(Object... args) {
    Transport transport = (Transport)args[0];

    transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() {
      @Override
      public void call(Object... args) {
        @SuppressWarnings("unchecked")
        Map<String, List<String>> headers = (Map<String, List<String>>)args[0];
        // modify request headers
        headers.put("Cookie", Arrays.asList("foo=1;"));
      }
    });

    transport.on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() {
      @Override
      public void call(Object... args) {
        @SuppressWarnings("unchecked")
        Map<String, List<String>> headers = (Map<String, List<String>>)args[0];
        // access response headers
        String cookie = headers.get("Set-Cookie").get(0);
      }
    });
  }
});


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM