Home  >  Article  >  WeChat Applet  >  Detailed explanation of websocket examples for WeChat applet development

Detailed explanation of websocket examples for WeChat applet development

Y2J
Y2JOriginal
2017-04-18 17:58:454858browse

Why do you need websocket?

For traditional real-time interactive games, or the behavior of the server actively sending messages (such as push services), if you want to do it on WeChat, you may use polling, but This consumes too many resources, a large number of requests also increases the burden on the server, and the delay problem is serious. If it is an app developed by oneself, in order to solve these problems, many teams will build their own sockets and use TCP long links and custom protocols to interact with the server in relatively real-time data. With a capable team, there is no big problem in adopting this approach. However, a small team may have to spend a lot of time debugging and solve many problems, which is not cost-effective.

H5 introduces webSocket to solve the problem of long links on the web page, and WeChat applet also supports websocket. This is a very important feature, so this series of articles will devote one article to discussing websockets.

WebSocket is essentially a TCP connection, which provides full-duplex data transmission. On the one hand, it can avoid the performance loss caused by frequent connection establishment and disconnection caused by polling. On the other hand, data can be transmitted in both directions in real time (because it is a long link), and WebSocket allows cross-domain communication (there is a potential here). Cross-domain security issues must be solved by the server). At present, browsers other than IE already support webSocket very well. After the WeChat applet is launched again, it will become more popular.

Let’s design a new demo, a more interesting mini-game, a multiplayer version of Minesweeper, to be precise, a multiplayer version of gold mining.

Detailed explanation of websocket examples for WeChat applet developmentThe rules of the game are as follows: Replace the thunder with gold. If you dig gold, you will get one point. Each person takes a turn (A has finished digging and it is B's turn, and B can click again after digging A). Click Even if the gold is yours, it will not explode. The game will continue until all the gold on the field has been mined. The game will not end. Just like minesweeper, the numbers also indicate how many golds are around, and then the user can guess which square may contain gold based on the numbers that have been revealed on the field.

The difficulty of this interactive game is that the user's click operations must be transmitted to the server, and the server must push it to other players' applications in real time. In addition, the user himself must also receive the data transmitted in real time during the other party's operation, so as not to click on the same grid repeatedly. To put it simply, you have to report the operation to the server, and the server has to push messages to you in real time. In order to simplify the entire model, we stipulate that players must take turns to click. After player A finishes clicking, it can be player B's turn. After player B completes the operation, player A can click.

We implement this function in several steps.

1. Implementation ideas

1. The first step is to generate a minesweeping map scene

This algorithm It’s relatively simple, let’s briefly describe it. By randomly picking a certain row or column, you can locate a grid and mark it as gold (-1 means gold). mimeCnt represents the amount of gold to be generated, and cyclically marks mimeCnt random grids in the same way. After the generation is completed, use a loop to scan these -1 grids and add 1 to the grids around them. Of course, they must be non-gold grids to add 1. The code is placed here .

Detailed explanation of websocket examples for WeChat applet development

increaseArround is used to add 1 to the grids surrounding this grid of gold. The implementation is relatively simple:

Detailed explanation of websocket examples for WeChat applet development

Execute genMimeArr(), and the randomly generated results are as follows:

Detailed explanation of websocket examples for WeChat applet development

-1 means gold. After looking at it, it seemed like there was no problem. Next, we will connect to webSocket.

(This is the js version. In fact, the work of generating map scenes is generated in the background. This js version is just a demonstration, but the algorithm is the same.)

2. We A server that supports webSocket is needed

In this example, we use python’s tornado framework to implement it (tornado provides the tornado.websocket module). Of course, readers can also use socket.io, a js language server designed specifically for webSocket. It is very simple to use. It also provides compatibility with browsers that do not support webSocket (flash or comet implementation).

The author prefers to use tornado. I have been doing background development for several years. One of the most used frameworks is it, the NIO model, and it is very lightweight. The same rps and java may require 700-800M. Memory, Tornado only needs 30-40M, so hundreds of Tornado services can be run on a machine with 4G memory, but Java, sorry, can only run 3 virtual machines. In the era of microservices, this is very important for small companies. Of course, if the reader is familiar with Java, you can also choose the netty framework to try it.

Another benefit of using tornado for webSocket is that it can support both webSocket and http protocols on the same service (port). The official demo code of tornado shows how to use both protocols at the same time. In this game, it can be used like this: the user enters the homepage and uses the http protocol to pull the current room number and data. Because the home page is the most opened, users who enter the home page may not necessarily play games. Therefore, there is no need to establish a webSocket link on the homepage. The webSocket link is mainly used to solve frequent requests and push operations. There is only one request operation on the home page. After selecting the room number, go to the next game page and start establishing the webSocket link.

3. Client

If you use the WeChat applet development tool, a domain name security error will be reported when connecting directly. Because there are restrictions within the tool, only safe domain names are required. The connection will be allowed. So in the same way, here we will continue to change the source code of the tool, and just change the relevant lines. The modification method is as follows:

Find this line of asdebug.js and change it to: if(false) .

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

Readers who are too lazy to modify can directly use the IDE that I have cracked. The code to initiate a websocket link is also relatively simple:

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

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

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

Received from the server Events triggered when a message is sent:

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

Message sending

Since establishing a link requires several handshakes and a certain amount of time, before wx.connectSocket succeeds, if wx.sendSocketMessage is sent directly The message will report an error. Here is a compatibility. If the connection has not been established successfully, an array will be used to save the information to be sent. When the link is established for the first time, the data will be traversed and the messages will be taken out and resent one by one. We encapsulate this logic into a send method, as follows:

`
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. Demo function analysis

1. Home page entry

In order to simplify the model and focus on webSocket, we make the homepage a form where you fill in the room number yourself. If readers have the time and ability, they can make the home page a room list and display how many people are playing in each room. Those with only one person can go in and play with him. You can even add a viewing mode later, click on other people's rooms to watch how others play.

Detailed explanation of websocket examples for WeChat applet development

Fill in the input component of the room number, add an event, get its value event.detail.value and setData to this page.

Click "Start Game", then store the room number in the app's globalData, and then wx.navigateTo to the main game page index.

This page is relatively simple.

2. Main game page

We encapsulate a websocket/connect.js module, specifically used to handle websocket links. There are two main methods, connect initiates a webSocket link, and send is used to send data.

index Main page:

Detailed explanation of websocket examples for WeChat applet development

Initialization state, 9x9 grid, each grid is actually a button button. The map scene data we generated corresponds to each grid. For example, 1 means there is gold in the surrounding area, 0 means there is no gold in the surrounding area, and -1 means that this grid is gold. Our goal is to find these -1. The more you find, the higher your score.

A security issue is discussed here. Believe it or not: most of the security measures taken on the front end are unreliable. The matrix in the picture above, the data behind each grid, should not be placed on the front end, because the js code can be debugged. You can set breakpoints on the corresponding variables, and then you can see the entire matrix data, and then know which grids If you are gold, you can cheat. This is very unfair. So the best way is to store these matrix data in the backend. Every time the user operates, the coordinates clicked by the user are sent to the background. The background then determines what data the corresponding coordinates are and returns them to the frontend. This interactive method that seems to involve a lot of data transmission actually does not waste resources, because every click operation of the user has to be reported to the background, so that another player in the game knows which grid you clicked. Data needs to be transmitted anyway, so coordinates must be transmitted. In this way, the front end does not need to know which grid contains what data, because the push message in the background will tell you.

In this way we bypass the problem of storing matrix data on the front end. But we still need an array to store the current matrix state, such as which grid has been opened and what data is inside, that is to say, we need to store the grids on the field that have been opened. So in the background, we need to store two data, one is all the matrix data, that is, the map scene data; the other is the current status data, which is used to synchronize the interfaces of both parties.

3. End page

The judgment condition for the end of the game is that all the gold on the field has been mined. This condition is also judged in the background.

Every time a user digs gold, there will be an additional judgment logic in the background, which is to see whether the gold is the last one. If so, send an over type message to all players in the game.

When the player terminal receives this message, it will end the current game and jump to the end page.

Detailed explanation of websocket examples for WeChat applet development

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

三、实现细节

1、代码结构

Detailed explanation of websocket examples for WeChat applet development

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

Detailed explanation of websocket examples for WeChat applet development

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

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

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

Detailed explanation of websocket examples for WeChat applet development

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

The above is the detailed content of Detailed explanation of websocket examples for WeChat applet development. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn