搜尋
首頁微信小程式微信開發微信小程式開發之websocket實例詳解

微信小程式開發之websocket實例詳解

Apr 18, 2017 pm 05:58 PM
websocket小程式開發微信

為什麼需要websocket?

傳統的即時互動的遊戲,或伺服器主動發送訊息的行為(如推播服務),如果想做在微信上,可能你會使用輪詢的方式進行,不過這太消耗資源,大量的請求也加重了伺服器的負擔,而且延遲問題比較嚴重。如果是自己開發的app,為了解決這些問題,很多團隊會自建socket,使用tcp長連結、自訂協定的方式與伺服器進行相對即時的資料互動。有能力的團隊,採用這種方式自然沒什麼大問題。不過小團隊可能要花很多時間去調試,要解決很多難題,這個在成本上就劃不來。

H5引進了webSocket來解決網頁端的長連結問題,而微信小程式也支援websocket。這是一個非常重要的特性,所以本系列的文章會特別拿出一篇來討論websocket。

webSocket本質上也是TCP連接,它提供全雙工的資料傳輸。一方面可以避免輪詢帶來的連接頻繁建立與斷開的性能損耗,另一方面數據可以是比較實時的進行雙向傳輸(因為是長鏈接),而且WebSocket允許跨域通信(這裡有個潛在的跨域安全性的問題,得靠服務端來解決)。目前除IE外的瀏覽器已經對webSocket支援得很好了,微信小程式再推一把之後,它會變得更加流行。

我們來設計一個新的demo,一個比較有趣的小遊戲,多人版掃雷,準確地講,多人版挖黃金。

微信小程式開發之websocket實例詳解遊戲規則是這樣的:把雷換成金子,挖到金子加一分,每人輪流一次(A挖完輪到B,B挖完A才能再點擊),點中金子就算你的,也不會炸,遊戲繼續,直到把場上所有的金子都挖完遊戲才結束。跟掃雷一樣,數字也是表示週邊有幾個金子,然後用戶根據場上已經翻出來的數字來猜哪一格可能有金子。

這種互動的遊戲困難在於,使用者的點擊操作都要傳到伺服器上,而且伺服器要即時的推送到其它玩家的應用程式上。另外用戶自己也要接收對方操作時即時傳過來的數據,這樣才不至於重複點中同一個格子。簡單講,就是你要上報操作給伺服器,而伺服器也要即時給你推訊息。為了簡化整個模型,我們規定玩家必須輪流點擊,玩家A點完後,才能輪到玩家B,玩家B操作完,玩家A才能點。

我們分幾步來實現這個功能。

一、實作想法

1、第一步,我們要先生成掃雷的地圖場景

這個演算法比較簡單,簡述一下。隨機取某行某列就可以定位一個格子,標記成金子(-1表示金子)。 mimeCnt表示要產生的金子的數量,用同樣的方式循環標記mimeCnt個隨機格子。生成完後,再用一個循環去掃描這些-1的格子,把它週邊的格子都加1,當然必須是非金子的格子才加1。代碼放在 這裡 。

微信小程式開發之websocket實例詳解

其中increaseArround用來把這格金子週邊的格子都加1,實作也比較簡單:

微信小程式開發之websocket實例詳解

執行genMimeArr(),隨機產生結果如下:

微信小程式開發之websocket實例詳解

-1表示金子。看了下貌似沒什麼問題。接下去,我們就要接入webSocket了。

(這個是js版本的,其實生成地圖場景的工作是在後台生成,這個js版本只是一個演示,不過演算法是一樣的。)

2、我們需要一個支援webSocket的服務端

本範例中,我們使用python的tornado框架來實作(tornado提供了tornado.websocket模組)。當然讀者也可以使用socket.io,專為webSocket設計的js語言的服務端,用起來非常簡單,它也對不支援webSocket的瀏覽器提供了相容(flash或comet實作)。

筆者本人比較喜歡使用tornado,做了幾年後台開發,使用最多的框架之一的就是它,NIO模型,而且非常輕量級,同樣的rps,java可能需要700-800M的內存,tornado只要30-40M,所以在一台4G內存的機子上可以跑上百個tornado服務,而java,對不起,只能跑3個虛擬機。微服務的時代,這點對小公司很重要。當然如果讀者本人對java比較熟悉的話,也可以選擇netty框架來嘗試。

webSocket用tornado的另一個好處是,它可以在同一個服務(連接埠)上同時支援webSocket及http兩種協定。 tornado的官方demo程式碼中展示了怎麼實作同時使用兩種協定。在本遊戲中,可以這麼用:使用者進入首頁,用http協議去拉取目前的房間號碼及資料。因為首頁是打開最多的,進了首頁的用戶不一定會玩遊戲。所以首頁還沒必要建立webSocket鏈接,webSocket鏈接主要用來解決頻繁請求及推送的操作。首頁只有一個請求操作。選了房間號碼後,進去下一個遊戲頁面再開始建立webSocket連結。

3、客戶端

使用微信小程式開發工具,直接連線是會報網域安全錯誤的,因為工具內部做了限制,對安全網域才會允許連線。所以同樣的,這裡我們也繼續改下工具的源碼,把相關的行改掉就行修改方式如下:

#找到asdebug.js的這一行,把它改成: if(false)即可。

`if (!i(r, "webscoket"))

懶得修改的讀者可以直接使用我破解過的IDE。 發起一個websocket連結的程式碼也比較簡單:

`wx.connectSocket({
url: webSocketUrl,
});
在调用这个请求代码之前,先添加下事件监听,这样才知道有没有连接成功:<br> `

wx.onSocketOpen(function(res){ console.log('websocket opened.'); });

rreee
`连接失败的事件:

1的訊息時觸發的事件:

wx.onSocketError(function(res){ console.log(&#39;websocket fail&#39;);
}) `
`
wx.onSocketMessage(function(res){
console.log(&#39;received msg: &#39; + res.data);
})
訊息發送

由於建立連結是需要幾次握手,需要一定的時間,所以在wx.connectSocket成功之前,如果直接wx.sendSocketMessage發送訊息會報錯,這裡做一個兼容,如果連接還沒建立成功,則用一個數組來保存要發送的信息;而鏈接第一次建立時,把數據遍歷一遍,把消息拿出來一個個補發。這個邏輯我們封裝成一個send方法,如下:

当链接建立之后,发送消息的方法如下:<br> `
二、demo功能解析#########1、首頁entry######

為了簡化模型,把重點放在webSocket上,我們把首頁做成自己填寫房間號碼的形式。讀者如果自己有時間和能力的話,可以把首頁做成一個房間列表,並顯示每個房間有多少人在玩,只有一人的可以進去跟他玩。甚至後面還可以加上觀看模式,點擊別人的房間進去觀看別人怎麼玩。

微信小程式開發之websocket實例詳解

填入房間號碼的input元件,新增一個事件,取得它的值event.detail.value後setData到本page裡面。

點擊“開始遊戲”,再把房間號碼存入app的globalData裡面,然後wx.navigateTo到主遊戲頁面index。

這個頁面比較簡單。

2、主遊戲頁面

我們封裝一個websocket/connect.js模組,專門用來處理websocket連結。主要有兩個方法,connect發起webSocket鏈接,send用來發送資料。

index主頁:

微信小程式開發之websocket實例詳解

初始化狀態,9x9的格子,每一個格子其實都是button按鈕。我們產生的地圖場景數據,分別對應每一格。例如1表示週邊的1個金子,0表示週邊沒有金子,-1表示這格是個金子,我們的目標就是找到這些-1。找越多得分越高。

這裡討論一個安全性問題。相信一句話:在前端做的安全措施大都是不靠譜的。上圖中的矩陣,每個格子背後的數據,不應該放在前端,因為js程式碼是可以調試的,可以下斷點在相應的變數上,就可以看到整個矩陣數據,然後就知道哪些格子是金子,就可以作弊,這是非常不公平的。所以最好的方法是把這些矩陣資料存在後端,每次使用者操作的時候,把使用者點擊的座標發到後台,後台再判斷對應的座標是什麼數據,再回到前端。這個看似有很多資料傳輸的互動方式,其實是不會浪費資源,因為用戶的每個點擊操作,本來就要上報到後台,這樣遊戲的另一玩家才知道你點了哪個格子。反正都是要傳數據的,所以一定要傳座標,這樣前端就完全沒有必要知道哪個格子是什麼數據,因為後台的推播訊息會告訴你。

這樣我們就繞過了前端存矩陣資料的問題。但是我們還是需要一個數組來儲存當前矩陣狀態的,例如哪個格子已經被翻開,裡面是什麼數據,也就是說要儲存場上已經被打開的格子。所以在後台,我們要儲存兩個數據,一個是所有的矩陣數據,也就是地圖場景資料;另一個是目前狀態的數據,這個要用來同步雙方的介面。

3、結束頁面

遊戲結束的判斷條件,就是場上所​​有的金子都被挖完了。這個條件也是在後台判斷的。

在每次使用者挖到金子的時候,後台都會多一個判斷邏輯,就是看這個金子是否是最後一個。如果是的話,就發送一個over類型的訊息給遊戲的所有玩家。

當玩家終端接收到這個訊息時,就會結束目前的遊戲,並跳到結束頁面。

微信小程式開發之websocket實例詳解

没有专门的设计师,随便网上偷了张图片贴上去,界面比较丑。下方显示自己的得分和当前的房间号。

三、实现细节

1、代码结构

微信小程式開發之websocket實例詳解

前端代码,分了几个模块:pages放所有的页面,common放通用的模块,mime放挖金子的主逻辑(暂时没用到),res放资源文件,websocket放webSocket相关的处理逻辑。

后台代码,读者稍微了解一下就行了,不讨论太多。里面我放了docker文件,熟悉docker的读者可以直接一个命令跑起整个服务端。笔者在自己的服务器上跑了这个webSocket服务,ip和端口已经写在前端代码里,读者轻虐。可能放不久,读者可以自己把这个服务跑起来。

2、消息收发

(1)消息协议

我们简单地定义下,消息的格式如下。 发送消息:

`{type: 'dig', …}

服务器返回的消息:

{errCode: 0, data: {type: 'dig', …} }

因为webSocket类型的消息跟传统的http请求不太一样,http请求没有状态,一个请求过去,一会儿就返回,返回的数据肯定是针对这个请求的。而webSocket的模型是这样的:客户端发过去很多请求,然后也不知道服务器返回的数据哪个是对应哪个请求,所以需要一个字段来把所有的返回分成多种类型,并进行相应的处理。

(2)发送消息

发送消息就比较容易了,上面我们定义了一个send方法及未连接成功时的简单的消息列表。

(3)接收消息

读者在阅读代码的时候,可能会有一个疑惑,websocket/connect.js里只有send发送方法,而没有接收推送消息的处理,那接收消息的处理在哪?怎么关联起来的?

websocket/目录里面还有另一个文件,msgHandler.js,它就是用来处理接收消息的主要处理模块:

微信小程式開發之websocket實例詳解

从服务器推送过来的消息,主要有这三种类型:1挖金子操作,可能是自己的操作,也可能是对方的操作,里面有一个字段isMe来表示是否是自己的操作。接收到这类消息时,会翻转地图上相应的格子,并显示出挖的结果。2创建或进入房间的操作,一个房间有两个用户玩,创建者先开始。3游戏结束的消息,当应用接收到这类消息时,会直接跳转到结束页面。

这个处理逻辑,是在websocket/connect.js的wx.onSocketMessage回调里关联上的。

在消息的收发过程中,每个消息交互,调试工具都会记录下来。可以在调试工具里看到,在NetWork->WS里就可以看到:

微信小程式開發之websocket實例詳解

3、前端挖金子

代码如下:

var websocket = require(&#39;../../websocket/connect.js&#39;); var msgReceived = require(&#39;../../websocket/msgHandler.js&#39;);
Page({
    data: {
        mimeMap: null,
        leftGolds: 0, // 总共有多少金子 score: 0, // 我的得分 roomNo: 0 // 房间号 },
    x: 0, // 用户点中的列 y: 0, // 用户点中的行 onLoad: function () { var roomNo = app.getRoomNo(); this.setData({
            roomNo: roomNo
        }); // test // websocket.send(&#39;before connection&#39;); if (!websocket.socketOpened) { // setMsgReceiveCallback websocket.setReceiveCallback(msgReceived, this); // connect to the websocket websocket.connect();
            websocket.send({
              type: &#39;create&#39; });
        } else {
            websocket.send({
              type: &#39;create&#39;,
              no: roomNo
            });
        }
    },
    digGold: function(event) { // 不直接判断,而把坐标传给后台判断 // 被开过的就不管了 if (event.target.dataset.value < 9) { return;
        } // 取到这格的坐标 this.x = parseInt(event.target.dataset.x); this.y = parseInt(event.target.dataset.y); console.log(this.x, this.y); // 上报坐标 this.reportMyChoice();
    },
    reportMyChoice: function() {
        roomNo = app.getRoomNo();
        websocket.send({
            type: &#39;dig&#39;,
            x: this.x,
            y: this.y,
            no: roomNo
        });
    },
});

在page的onLoad事件里,先更新界面上的房间号信息。然后开始我们的重点,websocket.connect发起webSocket链接,websocket是我们封装的模块。然后把我们msgHandler.js处理逻辑设置到服务端推送消息回调里面。接着,发送一个create消息来创建或加入房间。服务端会对这个消息做出响应,返回本房间的地图场景数据。

digGold是每个格子的点击事件处理函数。这儿有一个逻辑,一个格子周边最多有8个格子,所以每个格子的数据最大不可能大于8,上面代码中可以看到有一个9,这其实是为了跟0区分,用来表示场上目前的还没被翻开的格子的数据,用9来表示,当然你也可以用10,100都行。

wxml的矩阵数据绑定代码如下:

`
<view wx:for="{{mimeMap}}" wx:for-item="row" wx:for-index="i"
class="flex-container">
<button wx:for="{{row}}" wx:for-item="cell" wx:for-index="j"
class="flex-item {{cell<0?&#39;gold&#39;:&#39;&#39;}} {{cell<9?&#39;open&#39;:&#39;&#39;}}"
bindtap="digGold" data-x="{{j}}" data-y="{{i}}" data-value="{{cell}}">
{{cell<9?(cell<0?&#39;*&#39;:cell):"-"}}
</button>
</view>

4、服务端实现

简单的提一下就好,因为后台不是本系列文章的重点,虽然这个demo的开发也花了大半的时候在写后台。前后端的消息交互,借助了webSocket通道,传输我们自己定义格式的内容。上面有个截图显示了后台代码目录的结构,划分得比较随意,handlers里存放了的是主要的处理逻辑。webSocketHandler是入口,在它的on_message里,对收到的客户端的消息,根据类型进行分发,dig类型,分发到answerHandler去处理,create类型,分发到roomHandler里去处理。

还有一点稍微提一下,本例子中的后台webSocket消息处理也跟传统的http处理流程有一点不一样。就是在最后返回的时候,不是直接返回的,而是广播的形式,把消息发送给所有的人。比如用户A点击了格子,后台收到坐标后,会把这个坐标及坐标里的数据一起发送给房间里的所有人,而不是单独返回给上报坐标的人。只是会有一个isMe字段来告诉客户端是否是自己的操作。

总之,在做webSocket开发的时候,上面提到的,前后端都可能会有一些地方跟传统的http接口开发不太一样。读者尝试在做webSocket项目的时候,转换一下思维。

最后提下一个注意点:微信小程序的websocket链接是全局只能有一个,官方提示:“ 一个微信小程序同时只能有一个 WebSocket 连接,如果当前已存在一个 WebSocket 连接,会自动关闭该连接,并重新创建一个 WebSocket 连接。 ”

以上是微信小程式開發之websocket實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。