WebSocket 由來已久, 經常使用於 "服務器推" 場景。最近開始學習 WebSocket (從 tomcat examples 開始), 本文的主要目的是作學習筆記, 同時記錄一份開發指南。java
本文示例代碼見: https://github.com/hanyong/exercise/tree/websocketgit
咱們先來看看 HTTP。angularjs
一次 HTTP 請求過程以下:github
客戶端 | 服務器 | |
---|---|---|
1. | 客戶端創建到服務器的 TCP 鏈接 | |
2. | 客戶端發送請求 | |
3. | 客戶端等待響應 | |
4. | 服務器收到請求 | |
5. | 服務器發送響應 | |
6. | 客戶端收到響應 | |
7. | 請求結束 |
TCP 鏈接是支持雙向同時讀寫的全雙工協議, 可是咱們看傳統的 HTTP 協議有幾個問題:web
也就是說, 傳統的 HTTP 1.0/1.1 協議沒有充分利用 TCP 鏈接的能力.編程
HTTP 協議這樣的設計主要是簡化了編程模型, 想想傳統的 CGI 腳本, 一個腳本只要可以接受輸入, 產生輸出, 就能夠提供 web 服務。HTTP 協議缺乏 ISO 7 層網絡模型中的會話層, 動態 web 應用使用 cookie 來保存會話信息。HTTP/1.1 默認開啓長鏈接來優化性能, 但 HTTP 鏈接和請求依然是無狀態的。對傳統提供靜態內容服務, 或返回信息相對肯定的 web 應用而言, 這樣的設計並無問題, 或者說雖然有一些不足, 但尚能忍受。無狀態的設計也簡化了 HTTP 測試, 日誌回放也成爲重要的 HTTP 服務測試手段之一。api
直到 "服務器推" 場景的出現。服務器端信息隨時可能變化, 咱們但願將變化後最新的信息當即通知給客戶端。傳統的解決方案是客戶端不斷輪詢服務器, 如每秒 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 客戶端發送完請求後纔會監聽響應, 收到一次響應後即結束。常見的 HTTP 客戶端有:
curl
, 如 curl localhost:8080/http
.瀏覽器 js 客戶端, 如 angularjs 的 $http
服務.
$http.get("/http").then(function(resp) { vm.msg = resp.data; });
直接在瀏覽器輸入 URL.
回顧 "服務器推" 場景, websocket 與 HTTP 協議最大的不一樣在於服務器沒必要等待請求, 也再也不使用 "請求", "響應" 這樣的術語, 而改稱爲消息, 雙方均可以隨時互發消息。HTTP 客戶端不會一直監聽消息, 因此顯然不能做爲 websocket 客戶端 (且不說協議是否兼容)。要使用 websocket, 客戶端和服務器都須要改造。常見的 websocket 客戶端有:
瀏覽器 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(); }
再來看服務端開發, 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/