【Web開發須知】WebSocket 開發指南

WebSocket 由來已久, 經常使用於 "服務器推" 場景。最近開始學習 WebSocket (從 tomcat examples 開始), 本文的主要目的是作學習筆記, 同時記錄一份開發指南。java

    本文示例代碼見: https://github.com/hanyong/exercise/tree/websocketgit

HTTP 協議簡述

咱們先來看看 HTTP。angularjs

一次 HTTP 請求過程以下:github

  客戶端 服務器
1. 客戶端創建到服務器的 TCP 鏈接  
2. 客戶端發送請求  
3. 客戶端等待響應  
4.   服務器收到請求
5.   服務器發送響應
6. 客戶端收到響應  
7. 請求結束  

TCP 鏈接是支持雙向同時讀寫的全雙工協議, 可是咱們看傳統的 HTTP 協議有幾個問題:web

  1. 請求過程是串行的, 客戶端與服務器互相等待.
  2. 請求是單向的, 老是必須客戶端先發起請求.

也就是說, 傳統的 HTTP 1.0/1.1 協議沒有充分利用 TCP 鏈接的能力.編程

  1. HTTP 協議是無狀態的, 兩個請求是從同一個 TCP 鏈接發過來, 仍是從不一樣的 TCP 鏈接發過來, 對服務器來講應該是等價的.

    HTTP 協議這樣的設計主要是簡化了編程模型, 想想傳統的 CGI 腳本, 一個腳本只要可以接受輸入, 產生輸出, 就能夠提供 web 服務。HTTP 協議缺乏 ISO 7 層網絡模型中的會話層, 動態 web 應用使用 cookie 來保存會話信息。HTTP/1.1 默認開啓長鏈接來優化性能, 但 HTTP 鏈接和請求依然是無狀態的。對傳統提供靜態內容服務, 或返回信息相對肯定的 web 應用而言, 這樣的設計並無問題, 或者說雖然有一些不足, 但尚能忍受。無狀態的設計也簡化了 HTTP 測試, 日誌回放也成爲重要的 HTTP 服務測試手段之一。api

websocket 協議簡述

    直到 "服務器推" 場景的出現。服務器端信息隨時可能變化, 咱們但願將變化後最新的信息當即通知給客戶端。傳統的解決方案是客戶端不斷輪詢服務器, 如每秒 1 次。這種輪詢將產生許多額外的代價, 包括移動端流量收費, 而且編程模型也相對複雜。所以, 是時候開放 TCP 雙向通訊的能力了。咱們能夠從新寫一個 TCP 服務器, 使用新的協議來通訊。但也許是爲了複用 HTTP 的 80 端口, 依附現有 HTTP 生態圈, 讓 web 應用平滑升級, websocket 基於 HTTP 協議設計, 顧名思義就是基於 web HTTP 協議, 釋放原生 TCP socket 的能力。因此 websocket 一開始仍是按 HTTP 協議通訊, 隨後才轉換成 websocket。瀏覽器

一個 websocket 鏈接的創建過程以下:tomcat

  客戶端 服務器
1. 客戶端創建到服務器的 TCP 鏈接  
2. 客戶端請求將當前 TCP 鏈接用做 websocket  
3.   服務器收到請求, 贊成並確認將此 TCP 鏈接用做 websocket
4. 客戶端收到確認, HTTP 協議通訊結束  
5. 雙方使用 websocket 協議自由雙向通訊

websocket 可基於 HTTP 創建, 即 ws 協議, 也可基於 HTTPS 創建, 即 wss 協議, 果真是複用了 HTTP 的基礎設施。服務器

HTTP 與 websocket 客戶端

HTTP 客戶端發送完請求後纔會監聽響應, 收到一次響應後即結束。常見的 HTTP 客戶端有:

  1. curl, 如 curl localhost:8080/http.
  2. 瀏覽器 js 客戶端, 如 angularjs 的 $http 服務.

    $http.get("/http").then(function(resp) {
        vm.msg = resp.data;
    });
  3. 直接在瀏覽器輸入 URL.

    回顧 "服務器推" 場景, websocket 與 HTTP 協議最大的不一樣在於服務器沒必要等待請求, 也再也不使用 "請求", "響應" 這樣的術語, 而改稱爲消息, 雙方均可以隨時互發消息。HTTP 客戶端不會一直監聽消息, 因此顯然不能做爲 websocket 客戶端 (且不說協議是否兼容)。要使用 websocket, 客戶端和服務器都須要改造。常見的 websocket 客戶端有:

  1. 瀏覽器 js 客戶端。感謝瀏覽器廠商, 如今的主流瀏覽器都支持 websocket 。
    參考: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket

    var uri = "ws://" + window.location.host + "/ws";
    vm.ws = new WebSocket(uri);
    vm.ws.onmessage = function(event) {
        vm.msg = event.data;
        $scope.$apply();
    }

websocket 服務端開發

    再來看服務端開發, java 定義了一套 javax.servlet-api, 一個 HttpServlet 就是一個 HTTP 服務。java websocket 並不是基於 servlet-api 簡單擴展, 而是新定義了一套 javax.websocket-api。一個 websocket 服務對應一個 Endpoint。與ServletContext 對應, websocket-api 也定義了 WebSocketContainer, 而編程方式註冊 websocket 的接口是繼承自WebSocketContainer 的 ServerContainer。一個 websocket 能夠接受並管理多個鏈接, 所以可被視做一個 server。主流 servlet 容器都支持 websocket, 如 tomcat, jetty 等。看 ServerContainer api 文檔, 可從 ServletContext attribute 找到ServerContainer

閱讀全文直接點擊:http://click.aliyun.com/m/9971/

相關文章
相關標籤/搜索