Java後端使用socketio,實現小程式答題pk功能

  • 2020 年 12 月 17 日
  • 筆記

在使用socket.io跟前端通訊過程中,出現了一系列問題,現做下記錄。

一、功能需求是,在小程式端,用戶可相互邀請,進入房間後進行答題PK。實現方法是,用戶點擊邀請好友,建立連接,查詢當前是否有房間,有房間發送消息給兩人,匹配成功,開始pk。沒有房間新建房間返回,等待20秒,等待別人匹配。

       程式碼如下,先看配置,在application.yml配置文件中增加如下配置

 1 # host在本地測試可以設置為localhost或者本機IP,在Linux伺服器跑可換成伺服器IP
 2 socketio:
 3   host: 127.0.0.1    #監聽的ip
 4   port: 9999        #監聽埠
 5  # 設置最大每幀處理數據的長度,防止他人利用大數據來攻擊伺服器
 6   maxFramePayloadLength: 1048576
 7   # 設置http交互最大內容長度
 8   maxHttpContentLength: 1048576
 9   # socket連接數大小(如只監聽一個埠boss執行緒組為1即可)
10   bossCount: 1
11   workCount: 100
12   allowCustomRequests: true
13   # 協議升級超時時間(毫秒),默認10秒。HTTP握手升級為ws協議超時時間
14   upgradeTimeout: 1000000
15   # Ping消息超時時間(毫秒),默認60秒,這個時間間隔內沒有接收到心跳消息就會發送超時事件
16   pingTimeout: 6000000
17   # Ping消息間隔(毫秒),默認25秒。客戶端向伺服器發送一條心跳消息間隔
18   pingInterval: 25000

View Code

 

配置類

 1 package com.cwn.wethink.remy.handler;
 2 
 3 
 4 import com.corundumstudio.socketio.SocketConfig;
 5 import org.springframework.beans.factory.annotation.Value;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 
 9 import com.corundumstudio.socketio.SocketIOServer;
10 
11 /**
12  * @description:
13  * @author: m1575
14  * @create: 2020-11-11
15  **/
16 @Configuration
17 class SocketIOConfig {
18 
19     @Value("${socketio.host}")
20     private String host;
21 
22     @Value("${socketio.port}")
23     private Integer port;
24 
25     @Value("${socketio.bossCount}")
26     private int bossCount;
27 
28     @Value("${socketio.workCount}")
29     private int workCount;
30 
31     @Value("${socketio.allowCustomRequests}")
32     private boolean allowCustomRequests;
33 
34     @Value("${socketio.upgradeTimeout}")
35     private int upgradeTimeout;
36 
37     @Value("${socketio.pingTimeout}")
38     private int pingTimeout;
39 
40     @Value("${socketio.pingInterval}")
41     private int pingInterval;
42 
43     /**
44      * 以下配置在上面的application.properties中已經註明
45      * @return
46      */
47     @Bean
48     public SocketIOServer socketIOServer() {
49         SocketConfig socketConfig = new SocketConfig();
50         socketConfig.setTcpNoDelay(true);
51         socketConfig.setSoLinger(0);
52         com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
53         config.setSocketConfig(socketConfig);
54         config.setHostname(host);
55         config.setPort(port);
56         config.setBossThreads(bossCount);
57         config.setWorkerThreads(workCount);
58         config.setAllowCustomRequests(allowCustomRequests);
59         config.setUpgradeTimeout(upgradeTimeout);
60         config.setPingTimeout(pingTimeout);
61         config.setPingInterval(pingInterval);
62         return new SocketIOServer(config);
63     }
64 }

View Code

 

後台實現

  1 package com.cwn.wethink.remy.handler;
  2 
  3 import java.util.*;
  4 import java.util.concurrent.ConcurrentHashMap;
  5 import javax.annotation.PostConstruct;
  6 import javax.annotation.PreDestroy;
  7 import com.alibaba.fastjson.JSONObject;
  8 import com.corundumstudio.socketio.*;
  9 import com.cwn.wethink.pojo.entity.Question;
 10 import com.cwn.wethink.remy.entity.PkAgainGame;
 11 import com.cwn.wethink.remy.entity.PkAnswerTime;
 12 import com.cwn.wethink.remy.entity.PkGroup;
 13 import com.cwn.wethink.remy.entity.WxUserInfo;
 14 import com.cwn.wethink.remy.mapper.PkMapper;
 15 import com.cwn.wethink.remy.mapper.WxUserInfoMapper;
 16 import com.cwn.wethink.remy.service.RemyCourseService;
 17 import lombok.extern.slf4j.Slf4j;
 18 import org.springframework.beans.factory.annotation.Autowired;
 19 import org.springframework.stereotype.Service;
 20 
 21 @Service
 22 @Slf4j
 23 public class MessageEventHandler {
 24 
 25     // 用來存已連接的客戶端
 26     private static Map<Long, SocketIOClient> clientMap = new ConcurrentHashMap<>();
 27 
 28     @Autowired
 29     private SocketIOServer socketIOServer;
 30 
 31     @Autowired
 32     private PkMapper pkMapper;
 33 
 34     @Autowired
 35     private WxUserInfoMapper wxUserInfoMapper;
 36 
 37     @Autowired
 38     private RemyCourseService remyCourseService;
 39 
 40     /**
 41      * Spring IoC容器創建之後,在載入SocketIOServiceImpl Bean之後啟動
 42      * @throws Exception
 43      */
 44     @PostConstruct
 45     private void autoStartup() throws Exception {
 46         start();
 47     }
 48 
 49     /**
 50      * Spring IoC容器在銷毀SocketIOServiceImpl Bean之前關閉,避免重啟項目服務埠佔用問題
 51      * @throws Exception
 52      */
 53     @PreDestroy
 54     private void autoStop() throws Exception  {
 55         stop();
 56     }
 57 
 58     public void start() {
 59         // 監聽客戶端連接,同級挑戰比拼
 60         socketIOServer.addConnectListener(client -> {
 61             Long uid = Long.valueOf(getParamsByClient(client));
 62             log.info("connect come in,uid:{}",uid);
 63             //0為同級挑戰,1為邀請好友pk
 64             int type = 0;
 65             //房間號
 66             int pkId = 0;
 67             //從請求的連接中拿出參數
 68             Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
 69             List<String> list = params.get("type");
 70             if (list != null && list.size() > 0) {
 71                 type = Integer.valueOf(list.get(0));
 72             }
 73             List<String> list1 = params.get("pkId");
 74             if (list1 != null && list1.size() > 0) {
 75                 pkId = Integer.valueOf(list1.get(0));
 76             }
 77             if (uid != null) {
 78                 if (clientMap.containsKey(uid)) {
 79                     log.info(uid + "is reconnect");
 80                     clientMap.remove(uid);
 81                     clientMap.put(uid , client);
 82                 }else{
 83                     clientMap.put(uid, client);
 84                     log.info("clientMap:"+clientMap);
 85                     joinSendMessage(uid , client , type , pkId);
 86                 }
 87             }
 88         });
 89 
 90         // 監聽客戶端斷開連接
 91         socketIOServer.addDisconnectListener(client -> {
 92             Long uid = Long.valueOf(getParamsByClient(client));
 93             log.info("disconnect come in,uid:{}",uid);
 94             if (uid != null) {
 95                 log.info("uid is not null come in,uid:{}",uid);
 96                 clientMap.remove(uid);
 97                 client.disconnect();
 98                 //退出通知對手
 99                 Long usrEntId = 0l;
100                 PkGroup pkGroup = pkMapper.getPkGroupUserNewRoom(uid);
101                 if(pkGroup != null){
102                     log.info("pkGroup is not null come in,uid:{}",uid);
103                     if(uid == pkGroup.getInviteUsrEntId()){
104                         usrEntId = pkGroup.getAcceptUsrEntId();
105                     }else if(uid == pkGroup.getAcceptUsrEntId()){
106                         usrEntId = pkGroup.getInviteUsrEntId();
107                     }
108                 }
109                 if(usrEntId != null && usrEntId != 0l){
110                     log.info("usrEntId is not null come in,uid:{}",uid);
111                     log.info("socketIOClient usrEntId:" + usrEntId);
112                     JSONObject jsonObject = new JSONObject();
113                     SocketIOClient socketIOClient = clientMap.get(usrEntId);
114                     if(socketIOClient != null){
115                         jsonObject.put("disconnect" , 1);
116                         socketIOClient.sendEvent("ClientReceive" , jsonObject);
117                     }
118                 }
119                 if(clientMap.get(usrEntId) == null || usrEntId == null){
120                     if(pkGroup != null){
121                         PkGroup updatePkGroup = pkMapper.getPkGroupById(pkGroup.getId());
122                         updatePkGroup.setState(2);
123                         pkMapper.updatePkGroup(updatePkGroup);
124                         log.info("disconnect opponent is disconnect,uid:{}",uid);
125                     }
126                 }
127             }
128             log.info("disconnect is success,uid:{}",uid);
129         });
130 
131         // 處理自定義的事件,與連接監聽類似
132         // 此示例中測試的json收發 所以接收參數為JSONObject 如果是字元類型可以用String.class或者Object.class
133         socketIOServer.addEventListener("ServerReceive",JSONObject.class, (client, data, ackSender) -> {
134             JSONObject jsonObject = data;
135             if(data != null){
136                 String uid = jsonObject.getString("usrEntId");
137                 String action = jsonObject.getString("action");
138                 if("getAI".equals(action)){
139                     log.info("getAI come in,uid:{}",uid);
140                     //和人機pk返回
141                     botSendMessage(uid , client);
142                 }else if("challenge".equals(action)){
143                     log.info("challenge come in,uid:{}",uid);
144                     //pk過程中每做一道題返回消息給兩個人
145                     int pkId = 0;
146                     if(!"".equals(jsonObject.getString("pkId"))){
147                         pkId = Integer.valueOf(jsonObject.getString("pkId"));
148                     }
149                     if(pkId == 0){
150                         log.info("challenge pkId is 0");
151                         return;
152                     }
153                     long usrEntId = -1;
154                     if(!"".equals(jsonObject.getString("usrEntId"))){
155                         usrEntId = Long.valueOf(jsonObject.getString("usrEntId"));
156                     }
157                     if(usrEntId == -1){
158                         log.info("challenge usrEntId is -1");
159                         return;
160                     }
161                     int answer = 0;
162                     if(!"".equals(jsonObject.getString("answer"))){
163                         answer = Integer.valueOf(jsonObject.getString("answer"));
164                     }
165                     int time = 0;
166                     if(!"".equals(jsonObject.getString("time"))){
167                         time = Integer.valueOf(jsonObject.getString("time"));
168                     }
169                     int queResId = 0;
170                     if(!"".equals(jsonObject.getString("queResId"))){
171                         queResId = Integer.valueOf(jsonObject.getString("queResId"));
172                     }
173                     int orderNum = 0;
174                     if(!"".equals(jsonObject.getString("orderNum"))){
175                         orderNum = Integer.valueOf(jsonObject.getString("orderNum"));
176                     }
177                     int option = 0;
178                     if(!"".equals(jsonObject.getString("option"))){
179                         option = Integer.valueOf(jsonObject.getString("option"));
180                     }
181                     PkAnswerTime  pkAnswerNow = new PkAnswerTime();
182                     pkAnswerNow.setPkGroupId(pkId);
183                     pkAnswerNow.setUsrEntId(usrEntId);
184                     pkAnswerNow.setAnswer(answer);
185                     pkAnswerNow.setTime(time);
186                     pkAnswerNow.setQueResId(queResId);
187                     pkAnswerNow.setOrderNum(orderNum);
188                     pkAnswerNow.setOption(option);
189                     pkMapper.savePkAnswerTime(pkAnswerNow);
190                     PkGroup pkGroup = pkMapper.getPkGroupById(pkId);
191                     if(usrEntId == pkGroup.getInviteUsrEntId()){
192                         long acceptUsrEntId = pkGroup.getAcceptUsrEntId();
193                         judgeWinner(acceptUsrEntId , pkAnswerNow ,client);
194                     }else if(usrEntId == pkGroup.getAcceptUsrEntId()){
195                         long inviteUsrEntId = pkGroup.getInviteUsrEntId();
196                         judgeWinner(inviteUsrEntId , pkAnswerNow ,client);
197                     }
198                 }else if("again".equals(action)){
199                     log.info("again come in");
200                     //再來一局
201                     int pkId = Integer.valueOf(jsonObject.getString("pkId"));
202                     log.info("pkId:"+pkId+"uid:"+uid);
203                     againSendMessage(uid , pkId, client);
204                 }else if("skill".equals(action)){
205                     //使用技能
206                     int pkId = Integer.valueOf(jsonObject.getString("pkId"));
207                     //技能id
208                     int infoId = Integer.valueOf(jsonObject.getString("info"));
209                     skillSendMessage(uid , pkId , infoId);
210                 }
211             }
212         });
213 
214         socketIOServer.start();
215         log.info("socket.io初始化服務完成");
216     }
217 
218     public void stop() {
219         if (socketIOServer != null) {
220             socketIOServer.stop();
221             socketIOServer = null;
222         }
223         log.info("socket.io服務已關閉");
224     }
225 
226     /**
227      * 此方法為獲取client連接中的參數,可根據需求更改
228      * @param client
229      * @return
230      */
231     private String getParamsByClient(SocketIOClient client) {
232         // 從請求的連接中拿出參數(這裡的usrEntId必須是唯一標識)
233         Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
234         List<String> list = params.get("usrEntId");
235         if (list != null && list.size() > 0) {
236             return list.get(0);
237         }
238         return null;
239     }
240 
241     private synchronized void joinSendMessage(long usrEntId , SocketIOClient client , int type , int pkId){
242         // 給客戶端發送一條資訊 發送ConnectReceive事件 需要客戶端綁定此事件即可接收到消息
243         JSONObject jsonObject = new JSONObject();
244         Date date = new Date(new Date().getTime() - 20000);
245         PkGroup pkGroup = pkMapper.getPkGroupByState(usrEntId , type , date);
246         if(type != 0 && pkId != 0){
247             pkGroup = pkMapper.getPkGroupById(pkId);
248         }
249         if(type != 0 && pkId == 0){
250             pkGroup = null;
251         }
252         if(pkGroup != null){
253             pkGroup.setAcceptUsrEntId(usrEntId);
254             pkGroup.setState(1);
255             pkMapper.updatePkGroup(pkGroup);
256             long inviteUsrEntId = pkGroup.getInviteUsrEntId();
257             WxUserInfo invite = wxUserInfoMapper.queryWxUserInfoByUsrEntId(inviteUsrEntId);
258             List<Question> questions = remyCourseService.listGetRandomTopic(0);
259             jsonObject.put("state" , 1);
260             jsonObject.put("wxUserInfo" , invite);
261             jsonObject.put("questions" , questions);
262             jsonObject.put("pkId" , pkGroup.getId());
263             client.sendEvent("ConnectReceive",jsonObject);
264             SocketIOClient socketIOClient = clientMap.get(inviteUsrEntId);
265             WxUserInfo accept = wxUserInfoMapper.queryWxUserInfoByUsrEntId(usrEntId);
266             JSONObject acceptJson = new JSONObject();
267             acceptJson.put("state" , 1);
268             acceptJson.put("questions" , questions);
269             acceptJson.put("pkId" , pkGroup.getId());
270             acceptJson.put("wxUserInfo" , accept);
271             socketIOClient.sendEvent("ConnectReceive" , acceptJson);
272         }else{
273             PkGroup savePkGroup = new PkGroup();
274             savePkGroup.setInviteUsrEntId(usrEntId);
275             savePkGroup.setState(0);
276             savePkGroup.setCreateTime(new Date());
277             savePkGroup.setType(type);
278             pkMapper.savePkGroup(savePkGroup);
279             jsonObject.put("state" , 0);
280             jsonObject.put("pkId" , savePkGroup.getId());
281             client.sendEvent("ConnectReceive",jsonObject);
282         }
283     }
284 
285     private synchronized void botSendMessage(String uid , SocketIOClient client){
286         JSONObject jsonObject = new JSONObject();
287         PkGroup pkGroup = pkMapper.getPkGroupByUsrEntIdToAI(Long.valueOf(uid));
288         if(pkGroup != null){
289             log.info("getAI pkGroup is not null come in,uid:{}",uid);
290             pkGroup.setAcceptUsrEntId(0l);
291             pkGroup.setState(1);
292             pkMapper.updatePkGroup(pkGroup);
293             List<Question> questions = remyCourseService.listGetRandomTopic(0);
294             jsonObject.put("state" , 1);
295             jsonObject.put("questions" , questions);
296             jsonObject.put("pkId" , pkGroup.getId());
297             client.sendEvent("AIReceive",jsonObject);
298         }
299     }
300 
301     private synchronized void judgeWinner(long anotherEntId , PkAnswerTime  pkAnswerNow, SocketIOClient client){
302         log.info("judgeWinner come in,anotherEntId:{}",anotherEntId);
303         int pkId = pkAnswerNow.getPkGroupId();
304         int orderNum = pkAnswerNow.getOrderNum();
305         int answer = pkAnswerNow.getAnswer();
306         int time = pkAnswerNow.getTime();
307         long usrEntId = pkAnswerNow.getUsrEntId();
308         int option = pkAnswerNow.getOption();
309         JSONObject json = new JSONObject();
310         PkAnswerTime pkAnswerTime = pkMapper.getPkAnswerTimeByParam(anotherEntId , pkId , orderNum);
311         if(pkAnswerTime != null){
312             log.info("judgeWinner pkAnswerTime is not null come in,pkAnswerTime:{}",pkAnswerTime);
313             PkGroup pkGroup = pkMapper.getPkGroupById(pkId);
314             if(orderNum == 5){
315                 pkGroup.setState(2);
316                 pkMapper.updatePkGroup(pkGroup);
317             }
318             long winUsrEntId = -1;
319             if(pkAnswerTime.getAnswer() == 1 && answer == 1){
320                 if(time > pkAnswerTime.getTime()){
321                     winUsrEntId = anotherEntId;
322                 }else if(time < pkAnswerTime.getTime()){
323                     winUsrEntId = usrEntId;
324                 }else{
325                     winUsrEntId = -1;
326                 }
327             }else if(pkAnswerTime.getAnswer() == 1){
328                 winUsrEntId = anotherEntId;
329             }else if(answer == 1){
330                 winUsrEntId = usrEntId;
331             }else{
332                 winUsrEntId = -1;
333             }
334             json.put("winUsrEntId" , winUsrEntId);
335             json.put("pkId" , pkId);
336             json.put("usrEntId" , anotherEntId);
337             json.put("answer" , pkAnswerTime.getAnswer());
338             json.put("time" , pkAnswerTime.getTime());
339             json.put("option" , pkAnswerTime.getOption());
340             client.sendEvent("challengeReceive",json);
341             if(anotherEntId != 0){
342                 SocketIOClient socketIOClient = clientMap.get(anotherEntId);
343                 JSONObject acceptJson = new JSONObject();
344                 acceptJson.put("pkId" , pkId);
345                 acceptJson.put("usrEntId" , usrEntId);
346                 acceptJson.put("answer", answer);
347                 acceptJson.put("time", time);
348                 acceptJson.put("option",option);
349                 acceptJson.put("winUsrEntId",winUsrEntId);
350                 socketIOClient.sendEvent("challengeReceive" , acceptJson);
351             }
352             if(pkGroup.getInviteUsrEntId() == winUsrEntId){
353                 if(pkGroup.getInviteNum() != null){
354                     pkGroup.setInviteNum(pkGroup.getInviteNum() + 1);
355                 }else{
356                     pkGroup.setInviteNum(1);
357                 }
358             }else if(pkGroup.getAcceptUsrEntId() == winUsrEntId){
359                 if(pkGroup.getAcceptNum() != null){
360                     pkGroup.setAcceptNum(pkGroup.getAcceptNum() + 1);
361                 }else{
362                     pkGroup.setAcceptNum(1);
363                 }
364             }
365             pkMapper.updatePkNum(pkGroup);
366         }
367     }
368 
369     private synchronized void againSendMessage(String uid , int pkId , SocketIOClient client){
370         JSONObject json = new JSONObject();
371         long usrEntId = Long.valueOf(uid);
372         PkGroup pkGroup = pkMapper.getPkGroupById(pkId);
373         log.info("againSendMessage pkGroup:"+pkGroup);
374         long opponentId = -1;
375         if(pkGroup.getAcceptUsrEntId() != null){
376             if(usrEntId == pkGroup.getAcceptUsrEntId()){
377                 opponentId = pkGroup.getInviteUsrEntId();
378             }else{
379                 opponentId = pkGroup.getAcceptUsrEntId();
380             }
381         }
382         PkAgainGame pkAgainGame = pkMapper.getPkAgainGame(opponentId , pkId);
383         log.info("againSendMessage pkAgainGame:"+pkAgainGame);
384         if(pkAgainGame == null){
385             PkAgainGame againGame = new PkAgainGame();
386             againGame.setCreateTime(new Date());
387             againGame.setUsrEntId(usrEntId);
388             againGame.setPkGroupId(pkId);
389             pkMapper.savePkAgainGame(againGame);
390             json.put("usrEntId" , usrEntId);
391             json.put("state" , 0);
392             SocketIOClient socketIOClient = clientMap.get(opponentId);
393             log.info("againSendMessage socketIOClient:"+socketIOClient);
394             socketIOClient.sendEvent("AgainReceive" , json);
395         }else{
396             pkAgainGame.setOpponentUsrEntId(usrEntId);
397             pkMapper.updatePkAgainGame(pkAgainGame);
398             //創建房間
399             PkGroup savePkGroup = new PkGroup();
400             savePkGroup.setAcceptUsrEntId(usrEntId);
401             savePkGroup.setInviteUsrEntId(opponentId);
402             savePkGroup.setState(1);
403             savePkGroup.setCreateTime(new Date());
404             savePkGroup.setType(pkGroup.getType());
405             pkMapper.savePkGroup(savePkGroup);
406             List<Question> questions = remyCourseService.listGetRandomTopic(0);
407             log.info("againSendMessage questions:"+questions);
408             json.put("state" , 1);
409             json.put("questions" , questions);
410             json.put("pkId" , savePkGroup.getId());
411             if(opponentId == 0){
412                 json.put("wxUserInfo" , "");
413             }else{
414                 WxUserInfo invite = wxUserInfoMapper.queryWxUserInfoByUsrEntId(opponentId);
415                 json.put("wxUserInfo" , invite);
416             }
417             client.sendEvent("AgainReceive",json);
418             if(opponentId != 0 && opponentId != -1){
419                 SocketIOClient socketIOClient = clientMap.get(opponentId);
420                 JSONObject acceptJson = new JSONObject();
421                 acceptJson.put("state" , 1);
422                 acceptJson.put("questions" , questions);
423                 acceptJson.put("pkId" , savePkGroup.getId());
424                 WxUserInfo accept = wxUserInfoMapper.queryWxUserInfoByUsrEntId(usrEntId);
425                 acceptJson.put("wxUserInfo" , accept);
426                 log.info("againSendMessage socketIOClient:"+socketIOClient);
427                 socketIOClient.sendEvent("AgainReceive" , acceptJson);
428             }
429         }
430     }
431 
432     private void skillSendMessage(String uid , int pkId , int infoId){
433         JSONObject json = new JSONObject();
434         long usrEntId = Long.valueOf(uid);
435         PkGroup pkGroup = pkMapper.getPkGroupById(pkId);
436         log.info("skillSendMessage pkGroup:"+pkGroup);
437         long opponentId = -1;
438         if(usrEntId == pkGroup.getAcceptUsrEntId()){
439             opponentId = pkGroup.getInviteUsrEntId();
440         }else{
441             opponentId = pkGroup.getAcceptUsrEntId();
442         }
443         json.put("usrEntId" , usrEntId);
444         json.put("skill" , 1);
445         json.put("info" , infoId);
446         SocketIOClient socketIOClient = clientMap.get(opponentId);
447         log.info("skillSendMessage socketIOClient:"+socketIOClient);
448         socketIOClient.sendEvent("SkillReceive" , json);
449     }
450 }

View Code

 

  二、遇到的一些問題

    1、最初在發送消息給兩人時,有個人能收到消息,有個人收不到

剛開始clientMap是這樣聲明的:

private static Map<String, SocketIOClient> clientMap = new ConcurrentHashMap<>();

但我在查詢用戶SocketIOClient時使用的是long類型,所以一直沒查到用戶的SocketIOClient,也就發送消息發不過去。

後面改為
private static Map<Long, SocketIOClient> clientMap = new ConcurrentHashMap<>();

這樣聲明還是獲取不到,繼而檢查程式碼,開始返回給兩個人的資訊對象JSONObject,使用的同一個對象,雖然重新set了值,但還是返回了相同的對象。

 1 JSONObject jsonObject = new JSONObject();
 2 jsonObject.put("state" , 1);
 3 jsonObject.put("wxUserInfo" , invite);
 4 jsonObject.put("questions" , questions);
 5 jsonObject.put("pkId" , pkGroup.getId());
 6 client.sendEvent("ConnectReceive",jsonObject);
 7 SocketIOClient socketIOClient = clientMap.get(inviteUsrEntId);
 8 WxUserInfo accept = wxUserInfoMapper.queryWxUserInfoByUsrEntId(usrEntId);
 9 jsonObject.put("state" , 1);
10 jsonObject.put("questions" , questions);
11 jsonObject.put("pkId" , pkGroup.getId());
12 jsonObject.put("wxUserInfo" , accept);
13 socketIOClient.sendEvent("ConnectReceive" , jsonObject);

View Code

 

後改為重新new一個JSONObject對象,問題解決。

    2、本地測試沒問題,上了測試環境出現問題。連接時間超過1分鐘,會自動斷開連接。

後經查是伺服器使用了nginx,nginx默認連接60s會斷開連接。

需更改nginx配置,如下:

 1 location /socket.io {
 2                 proxy_pass http://172.17.0.2:9999;
 3                 proxy_set_header Host $host;
 4                 proxy_next_upstream off;
 5                 proxy_buffering off;
 6                 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 7 
 8                 proxy_http_version 1.1;
 9                 proxy_set_header Upgrade $http_upgrade;
10                 proxy_set_header Connection "upgrade";
11                 proxy_read_timeout 3600s;
12         }

View Code

proxy_read_timeout默認為60s,若需要長時間連接,改大點。
   三、前端程式碼示例

 1 <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
 2     <script type="text/javascript">
 3         const connectEvent = "ConnectReceive";
 4         const aiEvent = "AIReceive";
 5         const challengeEvent = "challengeReceive";
 6         const sendEvent = "ServerReceive";
 7         const againEvent = "AgainReceive";
 8         const clientEvent = "ClientReceive";
 9         const skillEvent = "SkillReceive";
10         var socket;
11         function socketClick() {
12             //連接伺服器,返回房間、題目資訊
13             socket = io.connect('//127.0.0.1:9999', {
14                 'force new connection': true,
15                 'query': 'usrEntId=' + 41 + '&type=' + 1
16             })
17 
18             socket.on(connectEvent, function (data) {
19                 //data:{pkId: 31,state: 0} 房間號、狀態為0表示創建了個房間,為1表示有房間並已加入
20                 //data:{pkId: 31,questions:[{},{}...],state: 1,wxUserInfo:{openId:,unionId:,nickName:,headImg:,empiricalValue:,usrEntId:,createTime:,medal:}}
21                 console.log(data)
22             })
23 
24             socket.on(clientEvent, function (data) {
25                 //data:{disconnect: 1} 對手退出了房間
26                 console.log(data)
27             })
28 
29             socket.on(skillEvent, function (data) {
30                 //data:{usrEntId:42 , skill: 1 , info:1} 對手id、使用了技能,技能id
31                 console.log(data)
32             })
33 
34             socket.on(aiEvent, function (data) {
35                 //data:{pkId: 31,questions:[{},{}...],state: 1} 房間號、題目集合、狀態
36                 console.log(data)
37             })
38 
39             //每道題答完接收消息
40             socket.on(challengeEvent, function (data) {
41                 //返回 data:{pkId: 31,winUsrEntId: 41,usrEntId:42,answer:1,time:3} 房間號、贏家id、對手id、答案1對0錯、時間
42                 console.log('ServerReceive成功')
43             })
44 
45             socket.on(againEvent, function (data) {
46                 //data:{state: 0,usrEntId: 41} state為0邀請資訊、邀請再來一局玩家id
47                 //data:{state: 1,wxUserInfo: {},questions:[{},{}...],pkId} state為1再來一局成功、對手資訊、題目、房間號
48                 console.log(data)
49             })
50 
51             socket.on(clientEvent, function (data) {
52                 //data:{disconnect: 1} 對手退出了房間
53                 console.log(data)
54             })
55 
56             //發送和人機pk消息到伺服器
57             send({
58                 action: 'getAI',
59                 usrEntId: 41
60             })
61 
62             //每道題答完發送消息到伺服器
63             send({
64                 action: 'challenge',
65                 usrEntId: 41,
66                 answer: 1,
67                 time: 6,
68                 pkId: 1,
69                 orderNum: 1,
70                 queResId: 1,
71                 option: 3
72             })
73             //再來一局
74             send({
75                 action: 'again',
76                 usrEntId: 41,
77                 pkId:1
78             })
79 
80             //發送技能
81             send({
82                 action: 'skill',
83                 usrEntId: 41,
84                 pkId:1
85             })
86 
87         }
88         function send(data){
89             socket.emit(sendEvent,data);
90         }
91         
92         function quitClick() {
93             var data={usrEntId:41};
94             socket.disconnect();
95         }
96     </script>

View Code