Maison  >  Article  >  Applet WeChat  >  Explication détaillée des exemples de websockets pour le développement d'applets WeChat

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

Y2J
Y2Joriginal
2017-04-18 17:58:454856parcourir

Pourquoi avez-vous besoin de websockets ?

Pour les jeux interactifs traditionnels en temps réel, ou le comportement des serveurs envoyant activement des messages (comme les services push), si vous souhaitez le faire sur WeChat, vous pouvez utiliser le sondage, mais Cela consomme trop de ressources, un grand nombre de requêtes augmente également la charge sur le serveur et le problème de retard est grave. S'il s'agit d'une application développée par soi-même, afin de résoudre ces problèmes, de nombreuses équipes construiront leurs propres sockets et utiliseront des liens longs TCP et des protocoles personnalisés pour interagir avec le serveur avec des données en temps relativement réel. Avec une équipe compétente, il n’y a pas de gros problème pour adopter cette approche. Cependant, une petite équipe peut devoir consacrer beaucoup de temps au débogage et à la résolution de nombreux problèmes, ce qui n'est pas rentable.

H5 introduit webSocket pour résoudre le problème des liens longs sur la page Web, et l'applet WeChat prend également en charge websocket. Il s'agit d'une fonctionnalité très importante, c'est pourquoi cette série d'articles consacrera un article à la discussion sur les websockets.

WebSocket est essentiellement une connexion TCP, qui permet une transmission de données en duplex intégral. D'une part, cela peut éviter la perte de performances causée par l'établissement et la déconnexion fréquents des connexions causées par les interrogations. D'autre part, les données peuvent être transmises dans les deux sens en temps réel (car il s'agit d'une longue liaison), et WebSocket permet les échanges croisés. -communication de domaine (il existe un potentiel ici). Les problèmes de sécurité inter-domaines doivent être résolus par le serveur). À l'heure actuelle, les navigateurs autres qu'IE prennent déjà très bien en charge webSocket. Après le nouveau lancement de l'applet WeChat, elle deviendra plus populaire.

Concevons une nouvelle démo, un mini-jeu plus intéressant, une version multijoueur du dragueur de mines, pour être précis, une version multijoueur de l'extraction de l'or.

Explication détaillée des exemples de websockets pour le développement d'applets WeChatLes règles du jeu sont les suivantes : Remplacez le tonnerre par de l'or. Si vous creusez de l'or, vous obtiendrez un point. Chaque personne prend son tour (A a fini de creuser et c'est le tour de B. , et B peut cliquer à nouveau après avoir creusé. A). Cliquez Même si l'or est à vous, il n'explosera pas jusqu'à ce que tout l'or sur le terrain soit extrait. Tout comme pour le dragueur de mines, les chiffres indiquent également combien d'or il y a autour, et l'utilisateur peut alors deviner quel carré peut contenir de l'or en fonction des chiffres qui ont été révélés sur le terrain.

La difficulté de ce jeu interactif est que les opérations de clic de l'utilisateur doivent être transmises au serveur, et le serveur doit les transmettre aux applications des autres joueurs en temps réel. De plus, l'utilisateur lui-même doit également recevoir les données transmises en temps réel lors du fonctionnement de l'autre partie, afin de ne pas cliquer à plusieurs reprises sur la même grille. Pour faire simple, vous devez signaler l’opération au serveur, et le serveur doit vous envoyer des messages en temps réel. Afin de simplifier l'ensemble du modèle, nous stipulons que les joueurs doivent cliquer à tour de rôle. Une fois que le joueur A a fini de cliquer, ce peut être le tour du joueur B. Une fois que le joueur B a terminé l'opération, le joueur A peut cliquer.

Nous implémentons cette fonction en plusieurs étapes.

1. Idées de mise en œuvre

1. Dans la première étape, nous devons générer une scène de carte de dragueur de mines

Ceci. algorithme C'est relativement simple, décrivons-le brièvement. En choisissant au hasard une certaine ligne ou colonne, vous pouvez localiser une grille et la marquer comme or (-1 signifie or). mimeCnt représente la quantité d'or à générer et marque cycliquement les grilles aléatoires mimeCnt de la même manière. Une fois la génération terminée, utilisez une boucle pour scanner ces grilles -1 et ajoutez 1 aux grilles qui les entourent. Bien sûr, il faut qu'elles soient des grilles non dorées pour ajouter 1. Le code est placé ici .

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

increaseArround permet d'ajouter 1 aux grilles entourant cette grille d'or La mise en œuvre est relativement simple :

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

Exécutez genMimeArr(), et les résultats générés aléatoirement sont les suivants :

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

-1 signifie or. Après l’avoir regardé, il semblait qu’il n’y avait aucun problème. Ensuite, nous nous connecterons à webSocket.

(Il s'agit de la version js. En fait, le travail de génération de la scène cartographique est généré en arrière-plan. Cette version js n'est qu'une démonstration, mais l'algorithme est le même.)

2. Nous Un serveur prenant en charge webSocket est requis

Dans cet exemple, nous utilisons le framework tornado de python pour l'implémenter (tornado fournit le module tornado.websocket). Bien entendu, les lecteurs peuvent également utiliser socket.io, un serveur de langage js conçu spécifiquement pour webSocket. Il est très simple à utiliser et offre également une compatibilité avec les navigateurs qui ne prennent pas en charge webSocket (implémentation Flash ou Comet).

L'auteur préfère utiliser tornado. Je fais du développement en arrière-plan depuis plusieurs années. L'un des frameworks les plus utilisés est celui-ci, et il est très léger. Le même rps et java peuvent nécessiter 700. -800 Mo de mémoire, Tornado n'a besoin que de 30 à 40 Mo, donc des centaines de services Tornado peuvent être exécutés sur une machine avec 4 Go de mémoire, mais Java, désolé, ne peut exécuter que 3 machines virtuelles. À l’ère des microservices, c’est très important pour les petites entreprises. Bien entendu, si le lecteur est familier avec Java, vous pouvez également choisir le framework netty pour l'essayer.

Un autre avantage de l'utilisation de tornado pour webSocket est qu'il peut prendre en charge les protocoles webSocket et http sur le même service (port). Le code de démonstration officiel de tornado montre comment utiliser les deux protocoles en même temps. Dans ce jeu, il peut être utilisé comme ceci : l'utilisateur accède à la page d'accueil et utilise le protocole http pour extraire le numéro et les données actuels de la chambre. Étant donné que la page d'accueil est la plus ouverte, les utilisateurs qui accèdent à la page d'accueil ne jouent pas nécessairement à des jeux. Par conséquent, il n'est pas nécessaire d'établir un lien webSocket sur la page d'accueil. Le lien webSocket est principalement utilisé pour résoudre les requêtes fréquentes et les opérations push. Il n’y a qu’une seule opération de demande sur la page d’accueil. Après avoir sélectionné le numéro de chambre, accédez à la page de jeu suivante et commencez à établir le lien webSocket.

3. Client

Si vous utilisez l'outil de développement d'applets WeChat, une erreur de sécurité du nom de domaine sera signalée lors de la connexion directe. Parce qu'il existe des restrictions dans l'outil, seuls les noms de domaine sécurisés sont requis. La connexion sera autorisée. Donc de la même manière, nous continuons ici à modifier le code source de l'outil, et changeons simplement les lignes pertinentes. La méthode de modification est la suivante :

Trouvez cette ligne d'asdebug.js et remplacez-la par : si (faux) .

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

Les lecteurs trop paresseux pour modifier peuvent utiliser directement l'IDE que j'ai cracké. Le code pour lancer un lien websocket est également relativement simple :

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

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

`连接失败的事件:
wx.onSocketError(function(res){ console.log('websocket fail');
}) `

Événements déclenchés lors de la réception d'un message du serveur :

`
wx.onSocketMessage(function(res){
console.log('received msg: ' + res.data);
})
当链接建立之后,发送消息的方法如下:ff9d32c555bb1d9133a29eb4371c1213 `

Message envoyé

L'établissement d'un lien nécessitant plusieurs poignées de main, il faut un un certain laps de temps, donc avant que wx.connectSocket ne réussisse, si vous envoyez un message directement avec wx.sendSocketMessage, une erreur sera signalée. Voici une compatibilité. Si la connexion n'a pas été établie avec succès, un tableau sera utilisé pour enregistrer. les informations à envoyer ; lors de la première création du lien, parcourir les données, retirer les messages et les réémettre un par un. Nous encapsulons cette logique dans une méthode d'envoi, comme suit :

`
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);
}
}

2. Analyse de la fonction de démonstration

1. Entrée de la page d'accueil

Afin de simplifier le modèle et de nous concentrer sur webSocket, nous avons fait de la page d'accueil un formulaire où vous pouvez renseigner vous-même le numéro de chambre. Si les lecteurs en ont le temps et les capacités, ils peuvent créer sur la page d'accueil une liste de salles et afficher le nombre de personnes qui jouent dans chaque salle. Ceux qui n'ont qu'une seule personne peuvent entrer et jouer avec elle. Vous pouvez même ajouter un mode de visualisation plus tard, cliquer sur les salles des autres pour regarder comment les autres jouent.

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

Remplissez le composant d'entrée du numéro de chambre, ajoutez un événement, obtenez sa valeur event.detail.value et setData sur cette page.

Cliquez sur « Démarrer le jeu », puis stockez le numéro de la salle dans les données globales de l'application, puis wx.navigateTo vers l'index de la page principale du jeu.

Cette page est relativement simple.

2. Page principale du jeu

Nous encapsulons un module websocket/connect.js, qui est spécialement utilisé pour gérer les liens websocket. Il existe deux méthodes principales : connect initie un lien webSocket et send est utilisé pour envoyer des données.

page principale de l'index :

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

État d'initialisation, grille 9x9, chaque grille est en fait un bouton. Les données de scène cartographique que nous avons générées correspondent à chaque grille. Par exemple, 1 signifie qu'il y a de l'or dans les environs, 0 signifie qu'il n'y a pas d'or dans les environs et -1 signifie que cette grille est en or. Notre objectif est de trouver ces -1. Plus vous en trouvez, plus votre score est élevé.

Un problème de sécurité est abordé ici. Croyez-le ou non : la plupart des mesures de sécurité prises en amont ne sont pas fiables. La matrice dans l'image ci-dessus, les données derrière chaque grille, ne doivent pas être placées sur le front-end, car le code js peut être débogué. Vous pouvez définir des points d'arrêt sur les variables correspondantes, puis vous pouvez voir l'intégralité des données de la matrice, et. alors sachez quelles grilles Si vous êtes en or, vous pouvez tricher. C'est très injuste. Le meilleur moyen est donc de stocker ces données matricielles dans le backend. Chaque fois que l'utilisateur opère, les coordonnées cliquées par l'utilisateur sont envoyées en arrière-plan. L'arrière-plan détermine ensuite quelles sont les données correspondantes et les renvoie au frontend. Cette méthode interactive qui semble impliquer beaucoup de transmission de données ne gaspille pas de ressources, car chaque clic de l'utilisateur doit être signalé en arrière-plan, afin qu'un autre joueur du jeu sache sur quelle grille vous avez cliqué. Les données doivent être transmises de toute façon, donc les coordonnées doivent être transmises. De cette façon, le frontal n'a pas besoin de savoir quelle grille contient quelles données, car le message push en arrière-plan vous le dira.

De cette façon, nous contournons le problème du stockage des données matricielles sur le front-end. Mais nous avons toujours besoin d'un tableau pour stocker l'état actuel de la matrice, par exemple quelle grille a été ouverte et quelles données se trouvent à l'intérieur, c'est-à-dire que nous devons stocker les grilles sur le champ qui a été ouvert. Ainsi, en arrière-plan, nous devons stocker deux données, l'une est toutes les données matricielles, c'est-à-dire les données de la scène cartographique ; l'autre est les données d'état actuel, qui sont utilisées pour synchroniser les interfaces des deux parties.

3. Page de fin

La condition pour juger de la fin du jeu est que tout l'or sur le terrain ait été extrait. Cette condition est également jugée en arrière-plan.

Chaque fois qu'un utilisateur creuse de l'or, il y aura une logique de jugement supplémentaire en arrière-plan, qui consiste à voir si l'or est le dernier. Si tel est le cas, envoyez un message de type overtype à tous les joueurs du jeu.

Lorsque le terminal du joueur reçoit ce message, il mettra fin au jeu en cours et passera à la page de fin.

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

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

三、实现细节

1、代码结构

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

前端代码,分了几个模块: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,它就是用来处理接收消息的主要处理模块:

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

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

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

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

Explication détaillée des exemples de websockets pour le développement d'applets WeChat

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: &#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 连接。 ”

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn