|
昨天抽空學(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)證。 //在流開(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(); }
public XmppSeverConnection(Socket sock)
: this() { m_Sock = sock; m_Sock.BeginReceive(buffer, 0, BUFFERSIZE, 0, new AsyncCallback(ReadCallback), null); m_Sock.SendTimeout = 100; }
<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="30e3b 3等待服務(wù)器返回消息后客戶(hù)端發(fā)送用戶(hù)名(由于在客戶(hù)端采用了異步調(diào)用 <iq xmlns="jabber:client" id="agsXMPP_1" type="get" to="localhost"> 4服務(wù)器端收到用戶(hù)名等待用戶(hù)提供密碼 <iq xmlns="jabber:client" from="localhost" type="result" id="agsXMPP_1"> 5客戶(hù)端提供加密后的密碼 <iq xmlns="jabber:client" id="agsXMPP_2" to="localhost" type="set"> 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), 項(xiàng)目解決方案和類(lèi)圖 ![]() ![]() 附錄: |
|
|
來(lái)自: icecity1306 > 《開(kāi)發(fā)資料》