电竞比分网-中国电竞赛事及体育赛事平台

分享

.net平臺(tái) 基于 XMPP協(xié)議的即時(shí)消息服務(wù)端簡(jiǎn)單實(shí)現(xiàn)

 icecity1306 2015-05-08

        昨天抽空學(xué)習(xí)了一下XMPP,在網(wǎng)上找了好久,中文的資料太少了所以做這個(gè)簡(jiǎn)單的例子,今天才完成。公司也正在準(zhǔn)備開(kāi)發(fā)基于XMPP協(xié)議的即時(shí)通訊工具所以也算是打一個(gè)基礎(chǔ)吧!如果你還沒(méi)有了解過(guò)XMPP請(qǐng)先閱讀附錄中鏈接的文章,本實(shí)例是基agsXMPP上開(kāi)發(fā)的,agsXMPP是C#寫(xiě)的支持開(kāi)源XMPP協(xié)議軟件,我們可以在agsXMPP上快速構(gòu)建自已的即時(shí)通訊平臺(tái),我的這個(gè)例子只是修改了服務(wù)器端,因?yàn)閍gsXMPP本身自帶的服務(wù)器端沒(méi)有實(shí)現(xiàn)聊天功能、簽名和登錄密碼認(rèn)證。

服務(wù)器端XmppSeverConnection類(lèi)事件

//在流開(kāi)始時(shí)觸發(fā),一般是最初的響應(yīng)流
streamParser.OnStreamStart += new StreamHandler(streamParser_OnStreamStart);

//在流結(jié)束時(shí)觸發(fā),一般是發(fā)送</stream:stream>并關(guān)閉套接字連接streamParser.OnStreamEnd += new StreamHandler(streamParser_OnStreamEnd);

//在接收到流結(jié)點(diǎn)時(shí)觸發(fā),這是用得最多的,常用的<message>消息,<Presence>出席消息,< IQ>請(qǐng)求應(yīng)答消息都在這里處理
streamParser.OnStreamElement += new StreamHandler(streamParser_OnStreamElement);

 

//此處處理大部份的消息,包括消息路由
private void streamParser_OnStreamElement(object sender, Node e)
        {
            Console.WriteLine("OnStreamElement: " + e.ToString());
            if (e.GetType() == typeof(Presence))
            {
             // 路由presences節(jié)
            }
            else if (e.GetType() == typeof(Message))
            {
                // 路由messages節(jié)
            }
            else if (e.GetType() == typeof(IQ))
            {
                //處理IQ節(jié)
            }
        }

 

 /// <summary>
        
/// IQ節(jié)處理函數(shù)
        
/// </summary>
        
/// <param name="iq">.</param>
        private void ProcessIQ(IQ iq)
        {
            if (iq.Query.GetType() == typeof(Auth))
            {
               Auth auth = iq.Query as Auth;
                this.Username = auth.Username.ToString();

                switch (iq.Type)
                {
                    case IqType.get:
                        iq.SwitchDirection();
                        iq.Type = IqType.result;
                        auth.AddChild(new Element("password"));
                        auth.AddChild(new Element("digest"));
                        Send(iq);
                        break;

                    case IqType.set:
                        // 進(jìn)行登錄認(rèn)證
                        if (AccountBus.CheckLogin(auth.Username, auth.Digest, this.SessionId))
                        {
                            iq.SwitchDirection();
                            iq.Type = IqType.result;
                            iq.Query = null;
                            Send(iq);

                            Console.WriteLine(auth.Username + "登錄了" + "   登錄時(shí)間:" + System.DateTime.Now.ToString());

                        }
                       else
                        {
//登錄失敗返回錯(cuò)誤信息
                            iq.SwitchDirection();
                            iq.Type = IqType.error;
                            iq.Query = null;
                            Send(iq);
                        }
                        break;
                }
            }
            else if (iq.Query.GetType() == typeof(Roster))
            {
                ProcessRosterIQ(iq);
            }
        }

 

/// <summary>
        
/// 處理IQ節(jié)的雜項(xiàng)數(shù)據(jù).
        
/// </summary>
        
/// <param name="iq">The iq.</param>
        private void ProcessRosterIQ(IQ iq)
        {
            if (iq.Type == IqType.get)
            {
                // 發(fā)送IQ節(jié)的雜項(xiàng)數(shù)據(jù)
              
//這里我用來(lái)下載好友列表
                iq.SwitchDirection();
                iq.Type = IqType.result;
                List<string> friendList = new List<string>();
                friendList = AccountBus.GetFriendName(this.username);
                foreach (string str in friendList)
                {
                    RosterItem ri = new RosterItem();
                    ri.Name = str.Trim();
                    ri.Subscription = SubscriptionType.both;
                    ri.Jid = new agsXMPP.Jid(str.Trim() + "@localhost");
                    ri.AddGroup("localhost");
                    iq.Query.AddChild(ri);
                }
                Send(iq);
            }
        }


 

服務(wù)器端開(kāi)啟監(jiān)聽(tīng)5222端口

 

 while (running)
                {
                    ////
                    allDone.Reset();
                    // Start an asynchronous socket to listen for connections.
                    Console.WriteLine("等待連接");

                    listener.BeginAccept(new AsyncCallback(AcceptCallback), null);

                    //// 等待客戶(hù)端連接                    
                     allDone.WaitOne();

                }


如果收到客戶(hù)端請(qǐng)求就異步調(diào)用AcceptCallback初始化套接字連接
,并為客戶(hù)端建立一個(gè)通信線(xiàn)程,新建初始化套接字連接采用異步調(diào)
用讀取套接字信息

 public XmppSeverConnection(Socket sock)
            : this()
        {
            m_Sock = sock;
            m_Sock.BeginReceive(buffer, 0, BUFFERSIZE, 0, new AsyncCallback(ReadCallback), null);
            m_Sock.SendTimeout = 100;
        }



客戶(hù)端與服務(wù)器端的交互過(guò)程


  1客戶(hù)端異步向服務(wù)器端發(fā)送連接請(qǐng)求

<stream:stream to='localhost' xmlns='jabber:client' xmlns:stream='http://etherx./streams' version='1.0' xml:lang='en'>

2服務(wù)器端收到請(qǐng)求,初始化回應(yīng)流,并隨機(jī)生成一相SessionID

 <stream:stream xmlns:stream="http://etherx./streams" from="localhost" id="30e3b8c0" >

3等待服務(wù)器返回消息后客戶(hù)端發(fā)送用戶(hù)名(由于在客戶(hù)端采用了異步調(diào)用
方式,所以UI界面感覺(jué)不到等待)

<iq xmlns="jabber:client" id="agsXMPP_1" type="get" to="localhost">
<query xmlns="jabber:iq:auth"><username>test</username></query></iq>

4服務(wù)器端收到用戶(hù)名等待用戶(hù)提供密碼

<iq xmlns="jabber:client" from="localhost" type="result" id="agsXMPP_1">
<query xmlns="jabber:iq:auth"><username>test</username><password />
<digest /></query></iq>

5客戶(hù)端提供加密后的密碼

<iq xmlns="jabber:client" id="agsXMPP_2" to="localhost" type="set">
<query xmlns="jabber:iq:auth"><username>test</username>
<digest>e66557d2b67256bf7e9b317a51b6101674a56b5e</digest>
<resource>MiniClient</resource></query></iq>

6服務(wù)器端從數(shù)據(jù)庫(kù)驗(yàn)證用戶(hù)名和密碼,并返回結(jié)果

iq xmlns="jabber:client" from="localhost" type="result" id="agsXMPP_2" />

7如果返回錯(cuò)誤,客戶(hù)端提示并終斷連接,否則客戶(hù)端發(fā)送響應(yīng)數(shù)據(jù)

8 服務(wù)器端返回?cái)?shù)據(jù)

9 客戶(hù)端發(fā)送狀態(tài),

10服務(wù)器收到狀態(tài),發(fā)送IQ節(jié)并通知其它用戶(hù).

項(xiàng)目解決方案和類(lèi)圖

 
 
 

附錄:
推薦使用Pandion作為客戶(hù)端
服務(wù)器端下載      客戶(hù)端下載
agsXMPP 源碼下載 
XMPP RFC 3920 可擴(kuò)展消息出席協(xié)議 
jabber官方網(wǎng)站

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多