# 8.2 WebSocket WebSocket 是 HTML5 的重要特性,它實現了基於瀏覽器的遠端 socket,它使瀏覽器和伺服器可以進行全雙工通訊,許多瀏覽器(Firefox、Google Chrome 和 Safari)都已對此做了支援。 在 WebSocket 出現之前,為了實現即時通訊,採用的技術都是“輪詢”,即在特定的時間間隔內,由瀏覽器對伺服器發出 HTTP Request,伺服器在收到請求後,回傳最新的資料給瀏覽器重新整理,“輪詢”使得瀏覽器需要對伺服器不斷髮出請求,這樣會佔用大量頻寬。 WebSocket 採用了一些特殊的報頭,使得瀏覽器和伺服器只需要做一個握手的動作,就可以在瀏覽器和伺服器之間建立一條連線通道。且此連線會保持在活動狀態,你可以使用 JavaScript 來向連線寫入或從中接收資料,就像在使用一個常規的 TCP Socket 一樣。它解決了 Web 即時化的問題,相比傳統 HTTP 有如下好處: - 一個 Web 客戶端只建立一個 TCP 連線 - Websocket 伺服器端可以推送(push)資料到 web 客戶端. - 有更加輕量級的頭,減少資料傳送量 WebSocket URL 的起始輸入是 ws://或是 wss://(在 SSL 上)。下圖展示了 WebSocket 的通訊過程,一個帶有特定報頭的 HTTP 握手被髮送到了伺服器端,接著在伺服器端或是客戶端就可以透過 JavaScript 來使用某種套介面(socket),這一套介面可被用來透過事件控制代碼非同步地接收資料。  圖 8.2 WebSocket 原理圖 ## WebSocket 原理 WebSocket 的協議頗為簡單,在第一次 handshake 透過以後,連線便建立成功,其後的通訊資料都是以”\x00″開頭,以”\xFF”結尾。在客戶端,這個是透明的,WebSocket 元件會自動將原始資料“掐頭去尾”。 瀏覽器發出 WebSocket 連線請求,然後伺服器發出迴應,然後連線建立成功,這個過程通常稱為“握手” (handshaking)。請看下面的請求和反饋資訊:  圖 8.3 WebSocket 的 request 和 response 資訊 在請求中的"Sec-WebSocket-Key"是隨機的,對於整天跟編碼打交道的程式設計師,一眼就可以看出來:這個是一個經過 base64 編碼後的資料。伺服器端接收到這個請求之後需要把這個字串連線上一個固定的字串: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 即:`f7cb4ezEAl6C3wRaU6JORA==`連線上那一串固定字串,產生一個這樣的字串: f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11 對該字串先用 sha1 安全雜湊演算法計算出二進位制的值,然後用 base64 對其進行編碼,即可以得到握手後的字串: rE91AJhfC+6JdVcVXOGJEADEJdQ= 將之作為回應標頭`Sec-WebSocket-Accept`的值反饋給客戶端。 ## Go 實現 WebSocket Go 語言標準套件裡面沒有提供對 WebSocket 的支援,但是在由官方維護的 go.net 子套件中有對這個的支援,你可以透過如下的命令取得該套件: go get golang.org/x/net/websocket WebSocket 分為客戶端和伺服器端,接下來我們將實現一個簡單的例子 : 使用者輸入資訊,客戶端透過 WebSocket 將資訊傳送給伺服器端,伺服器端收到資訊之後主動 Push 資訊到客戶端,然後客戶端將輸出其收到的資訊,客戶端的程式碼如下: ```html