• <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++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            上一篇分析客戶端登陸的過程。當用戶登陸成功后,聊天又是個什么過程呢?下面就來分析聊天時,客戶端與服務器端的交互過程。

            客戶端

            我們先來看看下,聊天發送消息的過程。當用戶在文本框內輸入文字,并回車就可以發送消息了

               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了,當焦點在entry(就用id來代表控件了),每次按下鍵盤都會觸發keypress()方法,方法接受一個事件e

            #2:route,決定客戶端向服務器端的哪個方法發送請求。

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

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

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

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

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




            #12:定義回調函數,處理服務器返回的結果對象data

            #13:清空entry

            #14:根據發送的對象判斷是否將發送的添加到聊天記錄中

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

            服務器端

            接下來,在看服務器端收到客戶端發送的請求是怎么處理的。打開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:解釋下參數 msg就是客戶端發送的對象,session就是服務器端與當前用戶的會話,next相當于把結果發送給客戶端 PS:next的真正功能我也描述不清,還請各位指點。

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

            #4:獲取ChannelService(管理Channel)

            #5-#10:把發送的信息,用戶名和發送信息的對象以及route。這里的route:onChat由服務器端定義的,客戶端監聽。每個客戶端都會監聽onXXX事件,監聽服務器發送的消息。這樣用戶發送的消息才能由服務器發送給其他用戶。

            #11:根據用戶發送的rid,獲取對應的channel

            #14-#25:判斷發送對象,是廣播還是發送給特定用戶。

            #26-28:將結果返回給客戶端

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

            PS:到此,這個demo的雛形就完成了,本來到這結束了……確實,如果你的servers.json里只有一個chat服務器,那么一切流程都可正常運行。但是,如果不只一個chat服務器,那肯定會遇到問題的,是不是信息發不出去,在看服務器端,報錯了!!

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

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

            很抱歉,channelService里并沒有channel,你一定很奇怪,當用戶登錄時,不是創建了channel了嗎,怎么會沒有呢?

            為了驗證,我把add和send時的app打印出來,對比

            image

            發現確實創建的channel沒有了,到底是怎么回事?

            再比較,就會發現還有一個不同之處。

            image

            你會發現,登陸和聊天時所在的服務器不一樣,難怪channel消失。

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

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

            #2:當服務器類型是chat,就會把路由到routeUtil.chat方法。

            然后在進入該方法,看看是怎么判斷用戶屬于哪個路由器的。

               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');//根據類型 獲取服務器列表
               5:  
               6:if(!chatServers || chatServers.length === 0) {//如果服務器列表不存在或為空,則調用回調函數cb,將錯誤傳給該回調
               7:         cb(new Error('can not find chat servers.'));
               8:return;
               9:     }
              10:  
              11:var res = dispatcher.dispatch(session.get('rid'), chatServers);//通過rid獲得具體的chat服務器
              12:     console.log("chat服務器:" + res.id);
              13:     cb(null, res.id);
              14: };

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

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

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

            是怎么分配chat-server,是隨機分配,還是自增分配?

            還有就是這句代碼是何時被調用的。

            希望各位能夠指點一下。

            少妇无套内谢久久久久| 天堂久久天堂AV色综合| 久久免费视频网站| 久久精品成人国产午夜| 久久精品国产99国产精品| 久久久91人妻无码精品蜜桃HD| 亚洲国产成人精品91久久久 | 久久青草国产手机看片福利盒子| www久久久天天com| 久久青青草原精品国产软件 | 国产69精品久久久久777| 国产精品岛国久久久久| 久久免费观看视频| 国产综合久久久久| 少妇久久久久久被弄到高潮| 久久男人Av资源网站无码软件| 免费国产99久久久香蕉| 亚洲va久久久久| 91精品国产综合久久香蕉| 中文字幕精品无码久久久久久3D日动漫| 亚洲日本久久久午夜精品| avtt天堂网久久精品| 久久AAAA片一区二区| 国产精品一区二区久久国产 | 久久久久久精品无码人妻| 亚洲国产精品一区二区久久| 狠狠色噜噜色狠狠狠综合久久| 精品久久久久国产免费| 1000部精品久久久久久久久| 久久国产免费直播| 亚洲国产精品成人久久蜜臀| segui久久国产精品| 久久99国内精品自在现线| 国产99久久久国产精品小说| 久久久久亚洲av成人无码电影| 91精品国产9l久久久久| 热re99久久6国产精品免费| 久久人人爽人人爽人人av东京热 | 国产成年无码久久久免费| 亚洲日韩欧美一区久久久久我| 久久久久久无码国产精品中文字幕 |