天天看點

WebSocket 長連接配接應用場景

沒事打開小程式,和附近的人剪刀石頭布,想來就來,想走就走。誰能成為武林高手?!

微信小程式提供了一套在微信上運作小程式的解決方案,有比較完整的架構、元件以及 API,在這個平台上面的想象空間很大。

騰訊雲拿到了小程式内測資格,研究了一番之後,發現微信支援 WebSocket 還是很值得玩味的。這個特性意味着我們可以做一些實時同步或者協作的小程式。

這篇文章分享一個簡單的剪刀石頭布的小遊戲的制作,希望能對想要在小程式中使用 WebSocket 的開發者有幫助。

WebSocket 長連接配接應用場景

剪刀石頭布遊戲效果

整個遊戲非常簡單,連接配接到伺服器後自動比對線上玩家(沒有則配置設定一個機器人),然後兩人進行剪刀石頭布的對抗遊戲。當對方進行拳頭選擇的時候,頭像會旋轉,這個過程使用 WebSocket 會變得簡單快速。

拿到了本小程式源碼的朋友可以嘗試自己運作起來。

WebSocket 長連接配接應用場景

整體部署架構

小程式的架構非常簡單,這裡有兩條網絡同步,一條是 HTTPS 通路,用于正常請求。對于 WebSocket 請求,會先走 HTTPS 後再切換協定到 WebSocket 的 TCP 連接配接,進而實作全雙工通信。

在微信小程式中,所有的網絡請求受到嚴格限制,不滿足條件的域名和協定無法請求,具體包括:

隻允許和在 MP 中配置好的域名進行通信,如果還沒有域名,需要注冊一個。

網絡請求必須走 HTTPS 協定,是以你還需要為你的域名申請一個證書。

域名注冊好之後,可以登入微信公衆平台配置通信域名了。

WebSocket 長連接配接應用場景

設定域名和證書

剪刀石頭布的伺服器運作代碼和配置已經打包成騰訊雲 CVM 鏡像,大家可以直接使用。

騰訊雲使用者可以免費領取禮包,體驗騰訊雲小程式解決方案。

WebSocket 長連接配接應用場景

設定鏡像

鏡像已包含「剪刀石頭布」和「小相冊」兩個小程式的伺服器環境與代碼,需要體驗兩個小程式的朋友無需重複部署

鏡像中已經部署了<code>nginx</code>,需要在<code>/etc/nginx/conf.d</code>下修改配置中的域名、證書、私鑰。

WebSocket 長連接配接應用場景

Nginx 中配置證書

配置完成後,即可啟動 nginx。

<code>nginx</code>

我們還需要添加域名記錄解析到我們的雲伺服器上,這樣才可以使用域名進行 HTTPS 服務。

在騰訊雲注冊的域名,可以直接使用雲解析控制台來添加主機記錄,直接選擇上面購買的 CVM。

WebSocket 長連接配接應用場景

修改 DNS 記錄

解析生效後,我們在浏覽器使用域名就可以進行 HTTPS 通路。

WebSocket 長連接配接應用場景

HTTPS 效果

在鏡像的 nginx 配置中(<code>/etc/nginx/conf.d</code>),已經把 <code>/applet/websocket</code>的請求轉發到<code>http://127.0.0.1:9595</code> 處理。我們需要把 Node 實作的 WebSocket 服務在這個端口裡運作起來。

進入鏡像中源碼位置:

<code>cd /data/release/qcloud-applet-websocket</code>

使用<code>pm2</code> 啟動服務:

<code>pm2 start process.json</code>

WebSocket 長連接配接應用場景

在微信開發者工具中修改小程式源碼中的 <code>config.js</code> 配置,把通訊域名修改成上面申請的域名。完成後點選調試即可連接配接到 WebSocket 服務進行遊戲。

WebSocket 長連接配接應用場景

配置完成後,運作小程式就可以看到成功搭建的提示!

WebSocket 長連接配接應用場景

成功效果

使用傳統的 HTTP 輪詢或者長連接配接的方式也可以實作類似伺服器推送的效果,但是這類方式都存在資源消耗過大或推送延遲等問題。而 WebSocket 直接使用 TCP 連接配接保持全雙工的傳輸,可以有效地減少連接配接的建立,實作真正的伺服器通信,對于有低延遲有要求的應用是一個很好的選擇。

目前浏覽器對 WebSocket 的支援程度已經很好,加上微信小程式的平台支援,這種可以極大提高用戶端體驗的通信方式将會變得更加主流。

Server 端需要實作 WebSocket 協定,才能支援微信小程式的 WebSocket 請求。鑒于 SocketIO 被廣泛使用,剪刀石頭布的小程式,我們選用了比較著名的 SocketIO 作為服務端的實作。

Socket IO 的使用比較簡單,僅需幾行代碼就可啟動服務。

但是,SocketIO 和一些其它的伺服器端實作,都有其配套的用戶端來完成上層協定的編碼解碼。但是由于微信的限制(不能使用 window 等對象), SocketIO 的用戶端代碼在微信小程式平台上是無法運作的。

經過對 SocketIO 通信進行抓包以及研究其用戶端源碼,筆者封裝了一個大約 100 行适用于微信小程式平台的 <code>WxSocketIO</code>類,可以幫助開發者快速使用 SocketIO 來進行 WebSocket 通信。

如果想要使用微信原生的 API,那麼在伺服器端也可以直接使用 ws 來實作 W3C 标準的接口。不過 SocketIO 支援多程序的特性,對于後續做橫向擴張是很有幫助的。騰訊雲在後面也會有計劃推出支援大規模業務需求的 WebSocket 連接配接服務,減小業務的部署成本。

實作一個多用戶端互動的服務,是需要把中間涉及到所有的消息類型都設計清楚的,就像是類似剪刀石頭布這樣一個小程式,都有下面這些消息類型。

消息

方向

說明

hello

c =&gt; s

用戶端連上後發送 hello 資訊,告知伺服器自己身份以及位置。

hi

s =&gt; c

伺服器響應用戶端打招呼,并且回報附近有多少人

join

用戶端請求加入一個房間進行遊戲

leave

用戶端請求退出房間

start

房間裡面全部人都 ready 後,會發送遊戲開始的信号,并且告知用戶端遊戲時間。

choice

用戶端選擇出剪刀、石頭還是布

face

用戶端更新自己的表情

movement

有使用者更新選擇或者更新表情會通知其它使用者

result

超過選擇時間後,遊戲結束,廣播遊戲結果

具體每個消息的參數可以參考源碼裡的<code>server/protocol.brief.md</code>

伺服器的邏輯很簡單:

收到使用者請求加入房間(<code>join</code>),就尋找還沒滿的房間

找到房間,則加入

沒找到房間,建立新房間

有使用者加入的房間檢查是否已滿,如果已滿,則:

給房間裡每個使用者發送開始遊戲的信号(<code>start</code>)

啟動計時器,計時器結束後進行遊戲結算

遊戲結算

兩兩之間 PK,赢方分數加一,輸方減一,最終得每個玩家基本得分 x

對于每個玩家,如果分數 x 大于 0,則視為勝利,連勝次數加一,否則連勝次數歸零

本局得分為分數 x 乘以連勝次數

發送本局遊戲結果給房間裡的每位玩家

微信小程式直接使用上面的協定,針對不同的場景進行渲染。整體的狀态機如下。

WebSocket 長連接配接應用場景

伺服器狀态機

狀态機整理清楚後,就是根據狀态機來控制什麼時候發送消息,接到消息後如何處理的問題了。具體實作請參照 <code>app/pages/game/game.js</code>裡的源碼。