# 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