• <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>

            eXile 的專欄

            [T] ICE實(shí)例學(xué)習(xí):Let's Chat! (2) 實(shí)現(xiàn)服務(wù)器


            服務(wù)器實(shí)現(xiàn):

                   服務(wù)器使用C++。注意它的結(jié)構(gòu):類 ChatRoom 實(shí)現(xiàn)了大部分的應(yīng)用邏輯。為了支持推模型與拉模型,服務(wù)器實(shí)現(xiàn)了類ChatSession 和類 PollingChatSession。 ChatRoom 調(diào)用 ChatRoomCallbackAdapter 對(duì)象的 send 函數(shù)來(lái)傳遞客戶消息,該對(duì)象隱藏了兩種模型之間的差異。

            ChatRoom 實(shí)現(xiàn):

                  ChatRoom是一個(gè)普通的C++對(duì)象,而不是一個(gè)Servant.
            // C++ 
            class ChatRoomCallbackAdapter { /*  */ }; 
            typedef IceUtil::Handle
            <ChatRoomCallbackAdapter> ChatRoomCallbackAdapterPtr; 
             
            class ChatRoom : public IceUtil::Shared 

            public
                
            void reserve(const string&); 
                
            void unreserve(const string&); 
                
            void join(const string&const ChatRoomCallbackAdapterPtr&); 
                
            void leave(const string&); 
                Ice::Long send(
            const string&const string&); 
             
            private
                typedef map
            <string, ChatRoomCallbackAdapterPtr> ChatRoomCallbackMap; 
             
                ChatRoomCallbackMap _members; 
                
            set<string> _reserved; 
                IceUtil::Mutex _mutex; 
            }; 
            typedef IceUtil::Handle
            <ChatRoom> ChatRoomPtr;

                  成員_reserverd是一個(gè)字符串集合,它存儲(chǔ)已經(jīng)建立回話,但是還沒(méi)有加入聊天室的客戶名。_members存儲(chǔ)當(dāng)前聊天室的所有用戶(已經(jīng)調(diào)用過(guò)join函數(shù)的用戶)。

                 成員函數(shù) reserve 和 unreserve 維護(hù) _reserved 集合。

            // C++ 
            void 
            ChatRoom::reserve(
            const string& name) 

                IceUtil::Mutex::Lock sync(_mutex); 
                
            if(_reserved.find(name) != _reserved.end() || _members.find(name) != _members.end()) 
                { 
                    
            throw string("The name " + name + " is already in use."); 
                } 
                _reserved.insert(name); 

             
            void 
            ChatRoom::unreserve(
            const string& name) 

                IceUtil::Mutex::Lock sync(_mutex); 
                _reserved.erase(name); 
            }


                 join操作添加用戶到聊天室。

            // C++ 
            void 
            ChatRoom::join(
            const string& name, const ChatRoomCallbackAdapterPtr& callback) 

                IceUtil::Mutex::Lock sync(_mutex); 
                IceUtil::Int64 timestamp 
            = IceUtil::Time::now().toMilliSeconds(); 
                _reserved.erase(name); 
             
                Ice::StringSeq names; 
                ChatRoomCallbackMap::const_iterator q; 
                
            for(q = _members.begin(); q != _members.end(); ++q) 
                { 
                    names.push_back((
            *q).first); 
                } 
             
                callback
            ->init(names); 
             
                _members[name] 
            = callback; 
             
                UserJoinedEventPtr e 
            = new UserJoinedEvent(timestamp, name); 
                
            for(q = _members.begin(); q != _members.end(); ++q) 
                { 
                    q
            ->second->join(e); 
                } 
            }


                  send實(shí)現(xiàn),同join實(shí)現(xiàn)非常類似:

            // C++ 
            Ice::Long 
            ChatRoom::send(
            const string& name, const string& message) 

                IceUtil::Mutex::Lock sync(_mutex); 
                IceUtil::Int64 timestamp 
            = IceUtil::Time::now().toMilliSeconds(); 
             
                MessageEventPtr e 
            = new MessageEvent(timestamp, name, message); 
                
            for(ChatRoomCallbackMap::iterator q = _members.begin(); q != _members.end(); ++q) 
                { 
                    q
            ->second->send(e); 
                } 
                
            return timestamp; 
            }

             

             類 ChatRoomCallbackAdapter

            // C++ 
            class ChatRoomCallbackAdapter : public IceUtil::Shared 

            public
                
            virtual void init(const Ice::StringSeq&= 0
                
            virtual void join(const UserJoinedEventPtr&= 0
                
            virtual void leave(const UserLeftEventPtr&= 0
                
            virtual void send(const MessageEventPtr&= 0
            };

            推模式 CallbackAdapter 實(shí)現(xiàn):
            class SessionCallbackAdapter : public ChatRoomCallbackAdapter 

            public
                SessionCallbackAdapter(
            const ChatRoomCallbackPrx& callback, const ChatSessionPrx& session)    : _callback(callback), _session(session) 
                { 
                } 
             
                
            void init(const Ice::StringSeq& users) 
                { 
                    _callback
            ->init_async(new AMICallback<AMI_ChatRoomCallback_init>(_session), users); 
                } 
             
                
            void join(const UserJoinedEventPtr& e) 
                { 
                    _callback
            ->join_async(new AMICallback<AMI_ChatRoomCallback_join>(_session), 
                                          e
            ->timestamp, 
                                          e
            ->name); 
                } 
             
                
            void leave(const UserLeftEventPtr& e) 
                { 
                    _callback
            ->leave_async(new AMICallback<AMI_ChatRoomCallback_leave>(_session), 
                                           e
            ->timestamp, 
                                           e
            ->name); 
                } 
             
                
            void send(const MessageEventPtr& e) 
                { 
                    _callback
            ->send_async(new AMICallback<AMI_ChatRoomCallback_send>(_session), 
                                          e
            ->timestamp, 
                                          e
            ->name, 
                                          e
            ->message); 
                } 
             
            private
                
            const ChatRoomCallbackPrx _callback; 
                
            const ChatSessionPrx _session; 
            };

                  看一下SessionCallbackAdapter的四個(gè)成員函數(shù),當(dāng)異步調(diào)用完成時(shí),都使用類AMICallback來(lái)接收通知。它的定義如下:
            template<class T> class AMICallback : public T 

            public
                AMICallback(
            const ChatSessionPrx& session) : _session(session) 
                { 
                }
                
            virtual void ice_response() 
                { 
                } 
             
                
            virtual void ice_exception(const Ice::Exception&
                { 
                    
            try 
                    { 
                        _session
            ->destroy(); // Collocated 
                    } 
                    
            catch(const Ice::LocalException&
                    { 
                    } 
                } 
             
            private
                
            const ChatSessionPrx _session; 
            };
                   當(dāng)用戶回調(diào)操作拋出異常,服務(wù)器立即銷毀客戶會(huì)話,即把該用戶趕出聊天室。這是因?yàn)椋坏┛蛻舻幕卣{(diào)對(duì)象出現(xiàn)了一次異常,它以后也就不可能再正常。


            推模式會(huì)話創(chuàng)建

                 現(xiàn)在來(lái)看一下會(huì)話創(chuàng)建。推模式的客戶使用Glacier2,所以要使用Glacier2的會(huì)話創(chuàng)建機(jī)制。Glacier2 允許用戶通過(guò)提供一個(gè)Glacier2::SessionManager對(duì)象的代理來(lái)自定義會(huì)話創(chuàng)建機(jī)制。通過(guò)設(shè)置Glacier2.SessionManager屬性來(lái)配置Gloacier2,就可以使用自己的會(huì)話管理器。會(huì)話管理器除了一個(gè)trivial構(gòu)造函數(shù)(設(shè)置聊天室指針),只有一個(gè)操作,create,Glacier2調(diào)用它來(lái)代理應(yīng)用的會(huì)話創(chuàng)建。 create 操作必須返回一個(gè)會(huì)話代理(類型為Glacier2::Session*)。實(shí)現(xiàn)如下:
            Glacier2::SessionPrx 
            ChatSessionManagerI::create(
            const string& name,
                                        
            const Glacier2::SessionControlPrx&
                                        
            const Ice::Current& c) 

                
            string vname; 
                
            try 
                { 
                    vname 
            = validateName(name); 
                    _chatRoom
            ->reserve(vname); 
                } 
                
            catch(const string& reason) 
                { 
                   
            throw CannotCreateSessionException(reason); 
                } 
             
                Glacier2::SessionPrx proxy; 
                
            try 
                { 
                    ChatSessionIPtr session 
            = new ChatSessionI(_chatRoom, vname); 
                    proxy 
            = SessionPrx::uncheckedCast(c.adapter->addWithUUID(session)); 
             
                    Ice::IdentitySeq ids; 
                    ids.push_back(proxy
            ->ice_getIdentity()); 
                    sessionControl
            ->identities()->add(ids); 
                } 
                
            catch(const Ice::LocalException&
                { 
                    
            if(proxy) 
                    { 
                        proxy
            ->destroy(); 
                    } 
                    
            throw CannotCreateSessionException("Internal server error"); 
                } 
                
            return proxy; 
            }

                 首先調(diào)用一個(gè)簡(jiǎn)單的幫助函數(shù) validateName, 來(lái)檢查傳遞的用戶名是否包含非法字符,并把它轉(zhuǎn)為大寫,然后調(diào)用 reserver函數(shù)把它加到聊天室的_reserved集合中。我們要監(jiān)視這些操作拋出的消息,并把它轉(zhuǎn)化為Glacide2::CannotCreateSessionException異常,即在create操作的異常規(guī)范聲明的異常。
                 接著實(shí)例化一個(gè)ChatSessionI對(duì)象(見(jiàn)下面)來(lái)創(chuàng)建會(huì)話。注意這個(gè)會(huì)話使用UUID作為對(duì)象標(biāo)識(shí),所以保證標(biāo)識(shí)符唯一。
                最后,添加這個(gè)新創(chuàng)建的會(huì)話標(biāo)識(shí),Gllacier2只通過(guò)它來(lái)轉(zhuǎn)發(fā)經(jīng)過(guò)這個(gè)會(huì)話的請(qǐng)求。實(shí)際上,“只轉(zhuǎn)發(fā)經(jīng)過(guò)這個(gè)會(huì)話的并且只到這個(gè)會(huì)話的請(qǐng)求”,這是一種安全的辦法:如果有惡意客戶能猜出另一個(gè)客戶會(huì)話的標(biāo)識(shí),它也不能向別的對(duì)象發(fā)送請(qǐng)求(可能在除了聊天服務(wù)器之外的服務(wù)器上)。如果出錯(cuò),就銷毀剛創(chuàng)建的會(huì)話對(duì)象,這樣避免了資源泄露。
                   這就是利用Glacier2創(chuàng)建會(huì)話的全部。如果你希望使用Glacier2的認(rèn)證機(jī)制,可以設(shè)置屬性Glacier2.PermissionsVerifier為執(zhí)行認(rèn)證的對(duì)象代理。(Glacier2提供一個(gè)內(nèi)置的權(quán)限驗(yàn)證器,NullPermissionsVerifier,可以檢查用戶名和密碼)。
                   圖:會(huì)話創(chuàng)建交互圖(略)

                   ChatSessionI類實(shí)現(xiàn)了ChatSession接口。
            class ChatSessionI : public ChatSession 

            public
                ChatSessionI(
            const ChatRoomPtr&const string&); 
             
                
            virtual void setCallback(const ChatRoomCallbackPrx&const Ice::Current&); 
                
            virtual Ice::Long send(const string&const Ice::Current&); 
                
            virtual void destroy(const Ice::Current&); 
             
            private
                
            const ChatRoomPtr _chatRoom; 
                
            const string _name; 
                ChatRoomCallbackAdapterPtr _callback; 
                
            bool _destroy; 
                IceUtil::Mutex _mutex; 
            }; 
            typedef IceUtil::Handle
            <ChatSessionI> ChatSessionIPtr;
                     構(gòu)造函數(shù)設(shè)置聊天室和用戶名,并把_destroy設(shè)置為False.
                  
                    由于Glacier2::create操作不允許傳遞代理,必須把創(chuàng)建會(huì)話和設(shè)置回調(diào)分成兩步。這是setCallback的實(shí)現(xiàn);
            void 
            ChatSessionI::setCallback(
            const ChatRoomCallbackPrx& callback, const Ice::Current& c) 

                IceUtil::Mutex::Lock sync(_mutex); 
                
            if(_destroy) 
                { 
                    
            throw Ice::ObjectNotExistException(__FILE__, __LINE__); 
                } 
             
                
            if(_callback || !callback) 
                { 
                    
            return
                } 
             
                Ice::Context ctx; 
                ctx[
            "_fwd"= "o"
                _callback 
            = new SessionCallbackAdapter(callback->ice_context(ctx), 
                                                       ChatSessionPrx::uncheckedCast( 
                                                           c.adapter
            ->createProxy(c.id))); 
                _chatRoom
            ->join(_name, _callback); 
            }

                  注意,在使用join傳遞代理之前,向客戶代理添加了一個(gè)值為 "o" 的_fwd上下文。它提示Glacier使用單向調(diào)用來(lái)轉(zhuǎn)發(fā)客戶回調(diào)。這樣比雙向調(diào)用更加有效。因?yàn)樗械幕卣{(diào)操作均為void返回值,所以可以單向調(diào)用。
                 服務(wù)器的回調(diào)為普通的雙向調(diào)用。這樣當(dāng)出錯(cuò)時(shí)可以通知服務(wù)器。當(dāng)客戶端出錯(cuò)時(shí),這個(gè)對(duì)結(jié)束客戶會(huì)話很有用。

                 一旦客戶調(diào)用了setCallback,就可以接收聊天室的各種行為通知。下為send實(shí)現(xiàn):

            Ice::Long 
            ChatSessionI::send(
            const string& message, const Ice::Current&

                IceUtil::Mutex::Lock sync(_mutex); 
                
            if(_destroy) 
                { 
                    
            throw Ice::ObjectNotExistException(__FILE__, __LINE__); 
                } 
                
            if(!_callback) 
                { 
                    
            throw InvalidMessageException("You cannot send messages until you joined the chat."); 
                } 
                
            string
                
            try 
                { 
                    msg 
            = validateMessage(message); 
                } 
                
            catch(const string& reason) 
                { 
                    
            throw InvalidMessageException(reason); 
                } 
                
            return _chatRoom->send(_name, msg); 
            }

             
                客戶要離開(kāi)聊天室,只要調(diào)用 destory.

            void 
            ChatSessionI::destroy(
            const Ice::Current& c) 

                IceUtil::Mutex::Lock sync(_mutex); 
                
            if(_destroy) 
                { 
                    
            throw Ice::ObjectNotExistException(__FILE__, __LINE__); 
                } 
                
            try 
                { 
                    c.adapter
            ->remove(c.id);
                    
            if(_callback == 0
                    { 
                        _chatRoom
            ->unreserve(_name); 
                    } 
                    
            else 
                    { 
                        _chatRoom
            ->leave(_name); 
                    } 
                } 
                
            catch(const Ice::ObjectAdapterDeactivatedException&
                { 
                    
            // No need to clean up, the server is shutting down. 
                } 
                _destroy 
            = true
            }

             

             

            posted on 2009-03-26 00:54 eXile 閱讀(3207) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 網(wǎng)絡(luò)開(kāi)發(fā)ICE

            導(dǎo)航

            <2008年10月>
            2829301234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678

            統(tǒng)計(jì)

            常用鏈接

            留言簿(18)

            隨筆分類

            隨筆檔案

            服務(wù)器編程

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            99麻豆久久久国产精品免费 | 色偷偷88888欧美精品久久久| 久久影院久久香蕉国产线看观看| 亚洲国产精品无码久久九九| 热re99久久6国产精品免费| 国内精品久久久久影院一蜜桃 | 国产成人精品久久亚洲高清不卡| 久久久久久毛片免费看| 久久精品国产亚洲AV久| 亚洲国产成人久久综合一| 7777精品伊人久久久大香线蕉| 国产精品久久99| 囯产极品美女高潮无套久久久| 国产999精品久久久久久| 亚洲中文字幕久久精品无码APP| 久久精品免费大片国产大片| 久久午夜无码鲁丝片| 亚洲伊人久久综合中文成人网| 久久97精品久久久久久久不卡| 97超级碰碰碰碰久久久久| 久久亚洲AV成人无码国产| 久久99国产精品久久99果冻传媒| 精品国产99久久久久久麻豆 | 久久AV高清无码| 久久久久久久波多野结衣高潮| 国产69精品久久久久99| 久久福利青草精品资源站| 久久精品无码一区二区无码| 97精品依人久久久大香线蕉97| 亚洲午夜精品久久久久久app| 看全色黄大色大片免费久久久| 国产毛片久久久久久国产毛片| 狠狠色丁香婷综合久久| 777米奇久久最新地址| 亚洲AV成人无码久久精品老人| 久久精品国产亚洲AV影院| 欧美久久久久久精选9999| 国产午夜精品久久久久九九电影| 99久久99久久精品国产片果冻| 国产精品99久久久久久www| 国产福利电影一区二区三区久久久久成人精品综合|