Heim > Artikel > WeChat-Applet > Detaillierte Erläuterung von Websocket-Beispielen für die WeChat-Applet-Entwicklung
Warum brauchen Sie WebSockets?
Für herkömmliche interaktive Echtzeitspiele oder das Verhalten von Servern, die aktiv Nachrichten senden (z. B. Push-Dienste), können Sie, wenn Sie dies auf WeChat tun möchten, Umfragen verwenden, aber Dies verbraucht zu viele Ressourcen, eine große Anzahl von Anfragen erhöht auch die Belastung des Servers und das Verzögerungsproblem ist schwerwiegend. Wenn es sich um eine selbst entwickelte App handelt, erstellen viele Teams zur Lösung dieser Probleme ihre eigenen Sockets und verwenden lange TCP-Verbindungen und benutzerdefinierte Protokolle, um relativ in Echtzeit mit dem Server zu interagieren. Mit einem leistungsfähigen Team ist die Übernahme dieses Ansatzes kein großes Problem. Allerdings muss ein kleines Team möglicherweise viel Zeit mit dem Debuggen und Lösen vieler Probleme verbringen, was nicht kosteneffektiv ist.
H5 führt webSocket ein, um das Problem langer Links auf der Webseite zu lösen, und das WeChat-Applet unterstützt auch Websocket. Da es sich hierbei um eine sehr wichtige Funktion handelt, wird in dieser Artikelserie ein Artikel der Erörterung von WebSockets gewidmet.
WebSocket ist im Wesentlichen eine TCP-Verbindung, die eine Vollduplex-Datenübertragung ermöglicht. Einerseits kann dadurch der Leistungsverlust vermieden werden, der durch häufiges Herstellen und Trennen von Verbindungen durch Abfragen verursacht wird. Andererseits können Daten in Echtzeit in beide Richtungen übertragen werden (da es sich um eine lange Verbindung handelt), und WebSocket ermöglicht Cross -Domänenkommunikation (hier besteht die Möglichkeit, dass domänenübergreifende Sicherheitsprobleme vom Server gelöst werden müssen). Derzeit unterstützen andere Browser als IE webSocket bereits sehr gut. Nach dem erneuten Start des WeChat-Applets wird es immer beliebter.
Lassen Sie uns eine neue Demo, ein interessanteres Minispiel, eine Multiplayer-Version von Minesweeper oder genauer gesagt eine Multiplayer-Version von Gold Mining entwerfen.
Die Spielregeln lauten wie folgt: Ersetzen Sie den Donner durch Gold und ein Punkt wird zum gegrabenen Gold hinzugefügt. Jede Person ist an der Reihe (A ist mit dem Graben fertig und B ist an der Reihe , und B kann erneut klicken, nachdem er A) gegraben hat. Auch wenn das Gold Ihnen gehört, wird es nicht explodieren. Das Spiel wird fortgesetzt, bis das gesamte Gold auf dem Feld abgebaut wurde. Genau wie bei Minesweeper geben die Zahlen auch an, wie viele Goldstücke sich in der Nähe befinden, und dann kann der Benutzer anhand der auf dem Spielfeld angezeigten Zahlen erraten, welches Quadrat möglicherweise Gold enthält.
Die Schwierigkeit dieses interaktiven Spiels besteht darin, dass die Klickvorgänge des Benutzers an den Server übertragen werden müssen und der Server sie in Echtzeit an die Anwendungen anderer Spieler weiterleiten muss. Darüber hinaus muss der Benutzer selbst die übermittelten Daten auch während des Betriebs der Gegenpartei in Echtzeit erhalten, um nicht wiederholt auf dasselbe Raster zu klicken. Vereinfacht ausgedrückt müssen Sie den Vorgang dem Server melden und der Server muss Ihnen in Echtzeit Nachrichten senden. Um das gesamte Modell zu vereinfachen, legen wir fest, dass Spieler abwechselnd klicken müssen. Nachdem Spieler A mit dem Klicken fertig ist, kann Spieler B an der Reihe sein.
Wir implementieren diese Funktion in mehreren Schritten.
1. Im ersten Schritt müssen wir eine Minensuchkartenszene generieren
Dies Algorithmus Es ist relativ einfach, lassen Sie es uns kurz beschreiben. Durch zufälliges Auswählen einer bestimmten Zeile oder Spalte können Sie ein Raster finden und es als Gold markieren (-1 bedeutet Gold). mimeCnt stellt die Menge an Gold dar, die generiert werden soll, und markiert mimeCnt-Zufallsgitter auf die gleiche Weise zyklisch. Nachdem die Generierung abgeschlossen ist, scannen Sie diese -1-Gitter mit einer Schleife und addieren Sie 1 zu den Gittern um sie herum. Natürlich müssen es Nicht-Gold-Gitter sein, um 1 hinzuzufügen. Der Code wird hier platziert.
increaseArround wird verwendet, um 1 zu den Gittern um dieses Goldgitter hinzuzufügen. Die Implementierung ist relativ einfach:
Führen Sie genMimeArr() aus und die zufällig generierten Ergebnisse lauten wie folgt:
-1 bedeutet Gold. Nachdem ich es mir angesehen hatte, schien es, als gäbe es kein Problem. Als nächstes stellen wir eine Verbindung zu webSocket her.
(Dies ist die js-Version. Tatsächlich wird die Arbeit zum Generieren der Kartenszene im Hintergrund generiert. Diese js-Version ist nur eine Demonstration, aber der Algorithmus ist der gleiche.)
2. Wir benötigen einen Server, der webSocket unterstützt
In diesem Beispiel verwenden wir das Tornado-Framework von Python, um es zu implementieren (Tornado stellt das Modul tornado.websocket bereit). Natürlich können Leser auch socket.io verwenden, einen speziell für webSocket entwickelten js-Sprachserver. Er ist sehr einfach zu verwenden und bietet auch Kompatibilität mit Browsern, die webSocket nicht unterstützen (Flash- oder Comet-Implementierung).
Der Autor verwendet am liebsten Tornado. Eines der am häufigsten verwendeten Frameworks ist das NIO-Modell, und es ist sehr leicht. Die gleichen RPS und Java erfordern möglicherweise 700 -800 MB Speicher, Tornado benötigt nur 30–40 MB, sodass Hunderte von Tornado-Diensten auf einer Maschine mit 4 GB Speicher ausgeführt werden können, aber Java kann leider nur drei virtuelle Maschinen ausführen. Im Zeitalter der Microservices ist dies für kleine Unternehmen sehr wichtig. Wenn der Leser mit Java vertraut ist, kann er natürlich auch das Netty-Framework auswählen, um es auszuprobieren.
Ein weiterer Vorteil der Verwendung von tornado für webSocket besteht darin, dass sowohl webSocket- als auch http-Protokolle auf demselben Dienst (Port) unterstützt werden können. Der offizielle Democode von Tornado zeigt, wie man beide Protokolle gleichzeitig nutzen kann. In diesem Spiel kann es folgendermaßen verwendet werden: Der Benutzer betritt die Homepage und ruft mithilfe des http-Protokolls die aktuelle Zimmernummer und die aktuellen Daten ab. Da die Startseite am häufigsten geöffnet wird, spielen Benutzer, die die Startseite betreten, nicht unbedingt Spiele. Daher ist es nicht erforderlich, einen WebSocket-Link auf der Homepage einzurichten. Der WebSocket-Link wird hauptsächlich zur Lösung häufiger Anfragen und Push-Vorgänge verwendet. Auf der Homepage gibt es nur einen Anforderungsvorgang. Nachdem Sie die Raumnummer ausgewählt haben, gehen Sie zur nächsten Spielseite und beginnen Sie mit der Einrichtung des webSocket-Links.
3. Client
Wenn Sie das WeChat-Applet-Entwicklungstool verwenden, wird beim direkten Herstellen einer Verbindung ein Domänennamen-Sicherheitsfehler gemeldet. Es sind nur sichere Domänennamen erforderlich. Auf die gleiche Weise modifizieren wir hier weiterhin den Quellcode des Tools und ändern nur die relevanten Zeilen. Die Änderungsmethode ist wie folgt:
Suchen Sie diese Zeile von asdebug.js und ändern Sie sie in: if (falsch) .
`if (!i(r, "webscoket"))
Leser, die zu faul zum Ändern sind, können direkt die IDE verwenden, die ich geknackt habe. Der Code zum Initiieren einer Websocket-Verknüpfung ist ebenfalls relativ einfach:
`wx.connectSocket({ url: webSocketUrl, });
在调用这个请求代码之前,先添加下事件监听,这样才知道有没有连接成功:ff9d32c555bb1d9133a29eb4371c1213 `
wx.onSocketOpen(function(res){ console.log('websocket open.'); });
`连接失败的事件:
wx.onSocketError(function(res){ console.log('websocket fail'); }) `
Ereignisse, die beim Empfang einer Nachricht vom Server ausgelöst werden:
` wx.onSocketMessage(function(res){ console.log('received msg: ' + res.data); })
当链接建立之后,发送消息的方法如下:ff9d32c555bb1d9133a29eb4371c1213 `
Nachricht gesendet
Da für den Verbindungsaufbau mehrere Handshakes erforderlich sind, dauert es einen Wenn Sie also eine Nachricht direkt mit wx.sendSocketMessage senden, wird ein Fehler gemeldet. Wenn die Verbindung nicht erfolgreich hergestellt wurde, wird ein Array zum Speichern verwendet die zu sendenden Informationen; wenn die Verbindung zum ersten Mal hergestellt wird, gehen Sie die Daten durch, nehmen Sie die Nachrichten heraus und senden Sie sie eine nach der anderen erneut. Wir kapseln diese Logik wie folgt in eine Sendemethode:
` function sendSocketMessage(msg) { if (typeof(msg) === 'object') { // 只能发送string msg = JSON.stringify(msg); } if (socketOpened) { // socketOpened变量在wx.onSocketOpen时设置为true wx.sendSocketMessage({ data:msg }); } else { // 发送的时候,链接还没建立 socketMsgQueue.push(msg); } }
1. Startseiteneintrag
Um das Modell zu vereinfachen und uns auf webSocket zu konzentrieren, haben wir auf der Homepage ein Formular erstellt, in das Sie die Zimmernummer selbst eingeben können. Wenn die Leser Zeit und Fähigkeit haben, können sie auf der Startseite eine Raumliste erstellen und anzeigen, wie viele Personen in jedem Raum spielen. Wer nur eine Person hat, kann hineingehen und mit ihm spielen. Sie können später sogar einen Anzeigemodus hinzufügen und auf die Räume anderer Personen klicken, um zu sehen, wie andere spielen.
Füllen Sie die Eingabekomponente der Raumnummer aus, fügen Sie ein Ereignis hinzu, rufen Sie dessen Wert event.detail.value ab und setzen Sie Data auf diese Seite.
Klicken Sie auf „Spiel starten“, speichern Sie dann die Raumnummer in den globalData der App und gehen Sie dann mit wx.navigateTo zum Index der Hauptspielseite.
Diese Seite ist relativ einfach.
2. Hauptspielseite
Wir kapseln ein websocket/connect.js-Modul, das speziell für die Verarbeitung von Websocket-Links verwendet wird. Es gibt zwei Hauptmethoden: Connect initiiert einen WebSocket-Link und Send wird zum Senden von Daten verwendet.
Index-Hauptseite:
Initialisierungsstatus, 9x9-Raster, jedes Raster ist eigentlich eine Schaltfläche. Die von uns generierten Kartenszenendaten entsprechen jedem Raster. Beispielsweise bedeutet 1, dass sich in der Umgebung 1 Gold befindet, 0 bedeutet, dass sich in der Umgebung kein Gold befindet, und -1 bedeutet, dass dieses Gitter Gold ist. Unser Ziel ist es, diese -1 zu finden. Je mehr Sie finden, desto höher ist Ihre Punktzahl.
Hier wird ein Sicherheitsproblem besprochen. Ob Sie es glauben oder nicht: Die meisten Sicherheitsmaßnahmen im Frontend sind unzuverlässig. Die Matrix im Bild oben, die Daten hinter jedem Raster, sollte nicht im Frontend platziert werden, da der js-Code debuggt werden kann. Sie können Haltepunkte für die entsprechenden Variablen festlegen, Sie können die gesamten Matrixdaten sehen und dann wissen Welche Gitter Wenn Sie Gold sind, können Sie betrügen. Das ist sehr unfair. Der beste Weg ist also, diese Matrixdaten im Backend zu speichern. Bei jeder Aktion des Benutzers werden die vom Benutzer angeklickten Koordinaten an den Hintergrund gesendet. Anschließend ermittelt der Hintergrund, um welche Daten es sich handelt, und gibt sie an das Frontend zurück. Diese interaktive Methode, die scheinbar viel Datenübertragung erfordert, verschwendet tatsächlich keine Ressourcen, da jeder Klickvorgang des Benutzers im Hintergrund gemeldet werden muss, damit ein anderer Spieler im Spiel weiß, auf welches Raster Sie geklickt haben. Es müssen sowieso Daten übertragen werden, also müssen Koordinaten übertragen werden. Auf diese Weise muss das Frontend nicht wissen, welches Raster welche Daten enthält, da die Push-Nachricht im Hintergrund es Ihnen mitteilt.
Auf diese Weise umgehen wir das Problem der Speicherung von Matrixdaten im Frontend. Aber wir brauchen immer noch ein Array, um den aktuellen Matrixstatus zu speichern, z. B. welches Gitter geöffnet wurde und welche Daten sich darin befinden, das heißt, wir müssen die Gitter auf dem Feld speichern, die geöffnet wurden. Im Hintergrund müssen wir also zwei Daten speichern, eines sind alle Matrixdaten, also die Kartenszenendaten, und das andere sind die aktuellen Statusdaten, die zur Synchronisierung der Schnittstellen beider Parteien verwendet werden.
3. Endseite
Voraussetzung für die Beurteilung des Endes des Spiels ist, dass das gesamte Gold auf dem Spielfeld abgebaut wurde. Auch dieser Zustand wird im Hintergrund beurteilt.
Jedes Mal, wenn ein Benutzer Gold gräbt, gibt es im Hintergrund eine zusätzliche Beurteilungslogik, die darin besteht, zu prüfen, ob das Gold das letzte ist. Wenn ja, senden Sie eine Overtype-Nachricht an alle Spieler im Spiel.
Wenn das Spielerterminal diese Nachricht empfängt, beendet es das aktuelle Spiel und springt zur Endseite.
没有专门的设计师,随便网上偷了张图片贴上去,界面比较丑。下方显示自己的得分和当前的房间号。
1、代码结构
前端代码,分了几个模块: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,它就是用来处理接收消息的主要处理模块:
从服务器推送过来的消息,主要有这三种类型:1挖金子操作,可能是自己的操作,也可能是对方的操作,里面有一个字段isMe来表示是否是自己的操作。接收到这类消息时,会翻转地图上相应的格子,并显示出挖的结果。2创建或进入房间的操作,一个房间有两个用户玩,创建者先开始。3游戏结束的消息,当应用接收到这类消息时,会直接跳转到结束页面。
这个处理逻辑,是在websocket/connect.js的wx.onSocketMessage回调里关联上的。
在消息的收发过程中,每个消息交互,调试工具都会记录下来。可以在调试工具里看到,在NetWork->WS里就可以看到:
3、前端挖金子
代码如下:
var websocket = require('../../websocket/connect.js'); var msgReceived = require('../../websocket/msgHandler.js'); 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('before connection'); if (!websocket.socketOpened) { // setMsgReceiveCallback websocket.setReceiveCallback(msgReceived, this); // connect to the websocket websocket.connect(); websocket.send({ type: 'create' }); } else { websocket.send({ type: 'create', 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: 'dig', 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?'gold':''}} {{cell<9?'open':''}}" bindtap="digGold" data-x="{{j}}" data-y="{{i}}" data-value="{{cell}}"> {{cell<9?(cell<0?'*':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 连接。 ”
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung von Websocket-Beispielen für die WeChat-Applet-Entwicklung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!