• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 311, comments - 0, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            上一篇分析客戶端登陸的過程。當(dāng)用戶登陸成功后,聊天又是個(gè)什么過程呢?下面就來分析聊天時(shí),客戶端與服務(wù)器端的交互過程。

            客戶端

            我們先來看看下,聊天發(fā)送消息的過程。當(dāng)用戶在文本框內(nèi)輸入文字,并回車就可以發(fā)送消息了

               1: $("#entry").keypress(function (e) {
               2:var route = "chat.chatHandler.send";
               3:var target = $("#usersList").val();
               4:if (e.keyCode != 13 /* Return */) return;
               5:var msg = $("#entry").attr("value").replace("\n", "");
               6:if (!util.isBlank(msg)) {
               7:             pomelo.request(route, {//route = "chat.chatHandler.send"
               8:                 rid: rid,
               9:                 content: msg,
              10:                 from: username,
              11:                 target: target
              12:             }, function (data) {
              13:                 $("#entry").attr("value", ""); // clear the entry field.
              14:if (target != '*' && target != username) {
              15:                     addMessage(username, target, msg);
              16:                     $("#chatHistory").show();
              17:                 }
              18:             });
              19:         }
              20:     });

            #1:entry就是聊天文本框的id了,當(dāng)焦點(diǎn)在entry(就用id來代表控件了),每次按下鍵盤都會(huì)觸發(fā)keypress()方法,方法接受一個(gè)事件e

            #2:route,決定客戶端向服務(wù)器端的哪個(gè)方法發(fā)送請(qǐng)求。

            #3:target,entry的上方有個(gè)名為users的下拉框,target就是下拉框的值了,決定用戶向誰發(fā)送消息。

            #4-#5:對(duì)輸入的字符判斷,如果不是回車就返回,如果是回車就將entry中的換行符替換成空字符串

            #6:util是client.js定義的一個(gè)對(duì)象,里面包含了一些對(duì)字符的處理方法,其中isBlank()是判斷字符串是否是空字符串

            #7:如果不是空字符串,就將這條消息發(fā)送給服務(wù)器,route就是#2所定義的服務(wù)器的處理方法 chat.chatHandelr.send

            #8-#11:客戶端將用戶所在的channel,發(fā)送的消息了,用戶名以及發(fā)送消息的對(duì)象封裝成對(duì)象,發(fā)送給服務(wù)器




            #12:定義回調(diào)函數(shù),處理服務(wù)器返回的結(jié)果對(duì)象data

            #13:清空entry

            #14:根據(jù)發(fā)送的對(duì)象判斷是否將發(fā)送的添加到聊天記錄中

            #15:在聊天記錄(id=chatHistory)顯示

            服務(wù)器端

            接下來,在看服務(wù)器端收到客戶端發(fā)送的請(qǐng)求是怎么處理的。打開chatofpomelo\game-server\app\servers\chat\handler\chatHandler.js

            找到handler.send

               1: handler.send = function(msg, session, next) {
               2:var rid = session.get('rid');
               3:var username = session.uid.split('*')[0];
               4:var channelService = this.app.get('channelService');
               5:var param = {
               6:         route: 'onChat',
               7:         msg: msg.content,
               8:         from: username,
               9:         target: msg.target
              10:     };
              11:     channel = channelService.getChannel(rid, false);
              12:
              13://the target is all users
              14:if(msg.target == '*') {
              15:         channel.pushMessage(param);
              16:     }
              17://the target is specific user
              18:else {
              19:var tuid = msg.target + '*' + rid;
              20:var tsid = channel.getMember(tuid)['sid'];
              21:         channelService.pushMessageByUids(param, [{
              22:             uid: tuid,
              23:             sid: tsid
              24:         }]);
              25:     }
              26:     next(null, {
              27:         route: msg.route
              28:     });
              29: };

            #1:解釋下參數(shù) msg就是客戶端發(fā)送的對(duì)象,session就是服務(wù)器端與當(dāng)前用戶的會(huì)話,next相當(dāng)于把結(jié)果發(fā)送給客戶端 PS:next的真正功能我也描述不清,還請(qǐng)各位指點(diǎn)。

            #2-#3:從session中取得roomID(rid)和用戶名usernmae,chatofpomelo\game-server\app\servers\connector\handler\entryHandler.js的enter()方法有對(duì)于session的設(shè)置

            #4:獲取ChannelService(管理Channel)

            #5-#10:把發(fā)送的信息,用戶名和發(fā)送信息的對(duì)象以及route。這里的route:onChat由服務(wù)器端定義的,客戶端監(jiān)聽。每個(gè)客戶端都會(huì)監(jiān)聽onXXX事件,監(jiān)聽服務(wù)器發(fā)送的消息。這樣用戶發(fā)送的消息才能由服務(wù)器發(fā)送給其他用戶。

            #11:根據(jù)用戶發(fā)送的rid,獲取對(duì)應(yīng)的channel

            #14-#25:判斷發(fā)送對(duì)象,是廣播還是發(fā)送給特定用戶。

            #26-28:將結(jié)果返回給客戶端

            其實(shí),分析這么多代碼,前面我寫的很詳細(xì),后面就寫的簡略了。分析完后可以發(fā)現(xiàn),其實(shí)交互部分情況類似,只要弄懂了其中一部分,其余的也就好懂了。

            PS:到此,這個(gè)demo的雛形就完成了,本來到這結(jié)束了……確實(shí),如果你的servers.json里只有一個(gè)chat服務(wù)器,那么一切流程都可正常運(yùn)行。但是,如果不只一個(gè)chat服務(wù)器,那肯定會(huì)遇到問題的,是不是信息發(fā)不出去,在看服務(wù)器端,報(bào)錯(cuò)了!!

            是不是channel為undefined?看上面的第11行

               1: channel = channelService.getChannel(rid, false);

            很抱歉,channelService里并沒有channel,你一定很奇怪,當(dāng)用戶登錄時(shí),不是創(chuàng)建了channel了嗎,怎么會(huì)沒有呢?

            為了驗(yàn)證,我把a(bǔ)dd和send時(shí)的app打印出來,對(duì)比

            image

            發(fā)現(xiàn)確實(shí)創(chuàng)建的channel沒有了,到底是怎么回事?

            再比較,就會(huì)發(fā)現(xiàn)還有一個(gè)不同之處。

            image

            你會(huì)發(fā)現(xiàn),登陸和聊天時(shí)所在的服務(wù)器不一樣,難怪channel消失。

            其實(shí),聊天和登陸一樣,用戶在發(fā)送消息時(shí),看上面客戶端代碼的第8行和第10行,會(huì)發(fā)現(xiàn)客戶端不只會(huì)發(fā)送消息,還會(huì)把用戶名username和rid同時(shí)發(fā)送給服務(wù)器端。服務(wù)器端會(huì)根據(jù)username和rid,實(shí)際上只有rid,判斷該用戶是位于哪臺(tái)chat-server上,這就是為什么game-server/app.js會(huì)有這幾行代碼

               1: app.configure('production|development', function () {
               2:// route configures
               3:     app.route('chat', routeUtil.chat);//routes的chat屬性對(duì)應(yīng)routeUtil.chat()方法 
               4:     app.filter(pomelo.timeout());
               5: });

            #2:當(dāng)服務(wù)器類型是chat,就會(huì)把路由到routeUtil.chat方法。

            然后在進(jìn)入該方法,看看是怎么判斷用戶屬于哪個(gè)路由器的。

               1: exp.chat = function(session, msg, app, cb) {
               2:  
               3:     console.log("uid = " + session.uid + " rid = " + session.get("rid"));
               4:var chatServers = app.getServersByType('chat');//根據(jù)類型 獲取服務(wù)器列表
               5:  
               6:if(!chatServers || chatServers.length === 0) {//如果服務(wù)器列表不存在或?yàn)榭眨瑒t調(diào)用回調(diào)函數(shù)cb,將錯(cuò)誤傳給該回調(diào)
               7:         cb(new Error('can not find chat servers.'));
               8:return;
               9:     }
              10:  
              11:var res = dispatcher.dispatch(session.get('rid'), chatServers);//通過rid獲得具體的chat服務(wù)器
              12:     console.log("chat服務(wù)器:" + res.id);
              13:     cb(null, res.id);
              14: };

            #11:之前的代碼,相信大家都明白了。我們直接看11行代碼,是不是很眼熟?dispatcher好像見過!還記得之前客戶端連接gate服務(wù)器,然后由gate服務(wù)器分配connector服務(wù)器,再返回其host和clientPort嗎?不錯(cuò),這里同樣是調(diào)用該方法,只不過connectors改成了chatServers。這樣根據(jù)傳入的rid,就可判斷用戶當(dāng)初登陸的那個(gè)chat-server,這樣也就能找到對(duì)應(yīng)的channel

            疑問:雖然解決了這一問題,但是還是不明白如果不添加對(duì)chat的路由,即沒有這行代碼:

               1: app.route('chat', routeUtil.chat);

            是怎么分配chat-server,是隨機(jī)分配,還是自增分配?

            還有就是這句代碼是何時(shí)被調(diào)用的。

            希望各位能夠指點(diǎn)一下。

            91麻豆国产精品91久久久| 无码人妻精品一区二区三区久久久 | 色婷婷综合久久久久中文字幕| 日韩精品久久久肉伦网站| 久久精品人妻一区二区三区| 老司机国内精品久久久久| 久久精品视频网| 亚洲成人精品久久| 国产69精品久久久久99| 久久精品国产99国产电影网| 久久久久综合网久久| 亚洲欧美精品伊人久久| 国产福利电影一区二区三区,免费久久久久久久精 | 亚洲av成人无码久久精品| 色妞色综合久久夜夜| 久久中文字幕人妻丝袜| 精产国品久久一二三产区区别| 久久人与动人物a级毛片| 色综合久久无码中文字幕| 国产精品无码久久综合 | 浪潮AV色综合久久天堂| 国产Av激情久久无码天堂| 国内精品久久久久影院免费| 99久久伊人精品综合观看| 久久国产视频网| 久久久久久久女国产乱让韩| 香蕉久久夜色精品升级完成| 国产V亚洲V天堂无码久久久| 久久93精品国产91久久综合| 亚洲日本va午夜中文字幕久久| 97久久国产综合精品女不卡| www.久久热.com| 久久免费视频一区| 人妻精品久久无码区| 久久―日本道色综合久久| 欧美亚洲另类久久综合婷婷| 亚洲精品白浆高清久久久久久| 色综合久久最新中文字幕| 四虎久久影院| 久久国产精品久久国产精品| 污污内射久久一区二区欧美日韩 |