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
- XMPP——(2)agsXMPP实现细节浅析
- XMPP——(4)agsXMPP和openfire连接
- agsXMPP 实现原理
- agsXMPP分析:agsXMPP简要指南 (转)
- agsxmpp
- XMPP——(1)大作业MyMeeting实现
- 浅析 Linux 中的时间编程和实现原理二—— 硬件和 GLibC 库的细节
- 细节成就卓越——浅析iPhone用户界面设计精粹
- 细节成就卓越——浅析iPhone用户界面设计精粹
- .Net开源IM项目:agsXMPP(C#)
- openfire xmpp sasl 浅析
- openfire与agsxmpp、qxmpp、psi等非spark的xmpp客户端通信
- XMPP 实现IM(三)
- 手机游戏《魔塔》实现细节——(0)序
- XMPP 实现IM(二)——openFire的配置和使用
- XMPP——Smack[1]离线消息实现
- XMPP——Smack[1]离线消息实现
- 添加XMPP的模块细节
- JavaScript自定义日期格式化函数
- Android 4.0新特性(中文)
- android学习笔记27:星级评分条
- 下雪了,可我却开心不起来
- NVIC寄存器组
- XMPP——(2)agsXMPP实现细节浅析
- 程序员的自我学习自我培训指南
- vs2008和QT及VTK实现三维重建之VS2008下QT的安装使用
- XMPP——(3)openfire和Spark
- 天书-碎片2
- XMPP——(4)agsXMPP和openfire连接
- SQLiteHelper
- 基于mini2440的ov9650摄像头裸机测试
- HTML5酷站欣赏及学习网站收集