XMPP——(2)agsXMPP实现细节浅析

来源:互联网 发布:时时彩选号软件 编辑:程序博客网 时间:2024/06/06 19:27

下面我们来深入到agsXMPP的实现细节,分两方面介绍Server和Client。

对于Client的编写,相对来说比较容易,agsXMPP SDK提供了XmppClientConnection类,直接调用就可以了。真正要做的是向该类的实例中加入事件处理函数,这样才能规定事件发生时,应该采取的动作。

该类中的事件如下:

Member

Description

OnAgentEnd

This event is raised when a response to an agents query which could contain multiple agentitems. Normally you show the items in a GUI. This event could be used to resume the suspended userinterface.

OnAgentItem

This event returns always a single AgentItem from a agents query result. This is from the old jabber protocol. Instead of agents Disco (Service Discovery) should be used in modern application. But still lots of servers use Agents.[!:]

OnAgentStart

This event is raised when a response to an agents query which could contain multiple agentitems. Normally you show the items in a GUI. This event could be used to suspend the UI for faster drawing.

OnAuthError

Event that occurs on authentication errors e.g. wrong password, user doesnt exist etc...

OnBinded

This event occurs after the resource was binded

OnClose

OnError

(Inherited from XmppConnection.)

OnIq

OnLogin

We are authenticated to the server now.

OnMessage

We received a message. This could be a chat message, headline, normal message or a groupchat message. There are also XMPP extension which are embedded in messages. e.g. X-Data forms.

OnPasswordChanged

This event ets fired after a ChangePassword Request was successful

OnPresence

We received a presence from a contact or chatroom. Also subscriptions is handles in this event.

OnReadSocketData

Data received from the Socket

(Inherited from XmppConnection.)

OnReadXml

a XML packet or text is received. This are no winsock events. The Events get generated from the XML parser

(Inherited from XmppConnection.)

OnRegistered

This event gets fired after a new account is registered

OnRegisterError

Event that occurs on registration errors

OnRegisterInformation

This event is fired when we get register information. You ca use this event for custom registrations.

OnRosterEnd

This event is raised when a response to a roster query is received. It notifies you that all RosterItems (contacts) are received now. When this event occurs you could Resume the GUI and show the normal mousepointer again.

OnRosterItem

This event is raised when a response to a roster query is received. This event always contains a single RosterItem. e.g. you have 150 friends on your contact list, then this event is called 150 times.

OnRosterStart

This event is raised when a response to a roster query is received. The roster query contains the contact list. This lost could be very large and could contain hundreds of contacts. The are all send in a single XML element from the server. Normally you show the contact list in a GUI control in you application (treeview, listview). When this event occurs you couls Suspend the GUI for faster drawing and show change the mousepointer to the hourglass

OnSaslEnd

OnSaslStart

OnSocketError

Event occurs on Socket Errors

OnStreamError

Event occurs on Xmpp Stream error elements

OnWriteSocketData

Data was sent to the socket for sending

(Inherited from XmppConnection.)

OnWriteXml

XML or Text is written to the Socket this includes also the keep alive packages (a single space)

(Inherited from XmppConnection.)

OnXmppConnectionStateChanged

This event just informs about the current state of the XmppConnection

(Inherited from XmppConnection.)

例如:对于OnReadXML事件相应的写法如下:

XmppClientConnection XmppCon;

XmppCon.OnReadXml   += new XmlHandler(XmppCon_OnReadXml);

其中XmppCon_OnReadXml是事件处理函数,当发生读Xml事件的时候,会调用该处理函数。

主要参见agsXMPPSDK/Samples/MiniClient。对于想要连接Google Talk服务器,客户端代码参见agsXMPP SDK/Samples/Gtalk。

 

对于Server的实现相对来说就复杂些,因为agsXMPP没有相关的实现。可能是出于不同的服务器实现的策略(例如转发,发送的消息)不同,所以就没有统一的实现。

实际上服务器所要做的就是发送和接收的数据做出相应处理,接收的数据应该向哪里转发或者丢掉、发送什么样的数据、向谁发送数据等等。主要参见agsXMPP SDK/Samples/Server实现。虽然看起来代码量要少于客户端,但是实现一个好的Server就不是那么容易了。

Sever的标准代码:

using System;

using System.IO;

using System.Text;

using System.Threading;

using System.Net;

using System.Net.Sockets;

 

using agsXMPP.protocol;

using agsXMPP.protocol.iq;

using agsXMPP.protocol.iq.auth;

using agsXMPP.protocol.iq.roster;

using agsXMPP.protocol.client;

 

using agsXMPP.Xml;

using agsXMPP.Xml.Dom;

 

namespace agsXMPP

{

     /// <summary>

     /// Zusammenfassung f黵XMPPSeverConnection.

     /// </summary>

     public class XmppSeverConnection

     {

         #region << Constructors >>

         public XmppSeverConnection()

         {       

              streamParser = new StreamParser();

              streamParser.OnStreamStart       += new StreamHandler(streamParser_OnStreamStart);

              streamParser.OnStreamEnd         += new StreamHandler(streamParser_OnStreamEnd);

              streamParser.OnStreamElement     += new StreamHandler(streamParser_OnStreamElement);  

           

         }

 

         public XmppSeverConnection(Socket sock) : this()

         {   

              m_Sock = sock;

              m_Sock.BeginReceive(buffer, 0, BUFFERSIZE, 0, new AsyncCallback(ReadCallback), null);       

         }

         #endregion

        private StreamParser              streamParser;

         private Socket                       m_Sock;

        private const int BUFFERSIZE = 1024;

        private byte[] buffer = new byte[BUFFERSIZE];

               

    

         public void ReadCallback(IAsyncResult ar)

         {       

              // Retrieve the state object and the handler socket

              // from the asynchronous state object

 

              // Read data from the client socket.

              int bytesRead = m_Sock.EndReceive(ar);

 

              if (bytesRead > 0)

              {                 

                   streamParser.Push(buffer, 0, bytesRead);

                  

                   // Not all data received. Get more.

                   m_Sock.BeginReceive(buffer, 0, BUFFERSIZE, 0, new AsyncCallback(ReadCallback), null);

              }

              else

              {

                   m_Sock.Shutdown(SocketShutdown.Both);

                   m_Sock.Close();

              }

         }

 

         private void Send(string data)

         {

              // Convert the string data to byte data using ASCII encoding.

              byte[] byteData = Encoding.UTF8.GetBytes(data);

 

              // Begin sending the data to the remote device.

              m_Sock.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), null);

         }

 

         private void SendCallback(IAsyncResult ar)

         {

              try

              {

                   // Complete sending the data to the remote device.

                   int bytesSent = m_Sock.EndSend(ar);

                   Console.WriteLine("Sent {0} bytes to client.", bytesSent);

 

              }

              catch (Exception e)

              {

                   Console.WriteLine(e.ToString());

              }

         }

    

        

         public void Stop()

         {

              Send("</stream:stream>");

//            client.Close();

//            _TcpServer.Stop();

 

              m_Sock.Shutdown(SocketShutdown.Both);

              m_Sock.Close();

         }

             

        

         #region << Properties and Member Variables >>

//       private int            m_Port             = 5222;      

         private string         m_SessionId        = null;

 

         public string SessionId

         {

              get

              {

                   return m_SessionId;

              }

              set

              {

                   m_SessionId = value;

              }

         }

         #endregion

 

         private void streamParser_OnStreamStart(object sender, Node e)

         {

              SendOpenStream();

         }

 

         private void streamParser_OnStreamEnd(object sender, Node e)

         {

 

         }

 

         private void streamParser_OnStreamElement(object sender, Node e)

         {

            Console.WriteLine("OnStreamElement: " + e.ToString());

              if (e.GetType() == typeof(Presence))

              {

                   // route presences here and handle all subscription stuff

              }

              else if (e.GetType() == typeof(Message))

              {

                   // route the messages here

 

              }

              else if (e.GetType() == typeof(IQ))

              {

                   ProcessIQ(e as IQ);

              }

         }

 

         private void ProcessIQ(IQ iq)

         {

              if(iq.Query.GetType() == typeof(Auth))

              {

                   Auth auth = iq.Query as Auth;

                   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:

                            // Here we should verify the authentication credentials

                            iq.SwitchDirection();

                            iq.Type = IqType.result;

                            iq.Query = null;

                            Send(iq);

                            break;

                   }

                  

              }

              else if(iq.Query.GetType() == typeof(Roster))

              {

                   ProcessRosterIQ(iq);

                  

              }

             

         }

 

         private void ProcessRosterIQ(IQ iq)

         {

              if (iq.Type == IqType.get)

              {

                   // Send the roster

                   // we send a dummy roster here, you should retrieve it from a

                   // database or some kind of directory (LDAP, AD etc...)

                   iq.SwitchDirection();

                   iq.Type = IqType.result;

                   for (int i=1; i<11;i++)

                   {

                       RosterItem ri = new RosterItem();

                       ri.Name = "Item " + i.ToString();

                       ri.Subscription = SubscriptionType.both;

                       ri.Jid = new Jid("item" + i.ToString() + "@localhost");

                       ri.AddGroup("localhost");

                       iq.Query.AddChild(ri);

                   }

                   for (int i=1; i<11;i++)

                   {

                       RosterItem ri = new RosterItem();

                       ri.Name = "Item JO " + i.ToString();

                       ri.Subscription = SubscriptionType.both;

                       ri.Jid = new Jid("item" + i.ToString() + "@jabber.org");

                       ri.AddGroup("JO");

                       iq.Query.AddChild(ri);

                   }

                   Send(iq);

              }

         }

 

         private void SendOpenStream()

         {

             

              // Recv:<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='myjabber.net' id='1075705237'>

             

              // Send the Opening Strem to the client

              string ServerDomain = "localhost";

             

              this.SessionId = agsXMPP.SessionId.CreateNewId();

             

             

              StringBuilder sb = new StringBuilder();

 

              sb.Append( "<stream:stream from='");

              sb.Append( ServerDomain );

             

              sb.Append( "' xmlns='" );

              sb.Append( Uri.CLIENT );

             

              sb.Append( "' xmlns:stream='" );

              sb.Append( Uri.STREAM );

             

              sb.Append( "' id='" );

              sb.Append( this.SessionId );

             

              sb.Append( "'>" );

 

              Send( sb.ToString() );

         }

 

         private void Send(Element el)

         {

              Send(el.ToString());

         }

 

     }

}

 

于208实验室

2012/1/5

原创粉丝点击