agsXMPP致力於創建一個輕量、快速的跨平臺類庫,用於XMPP協議。
通過下面的三項技術,agsXMPP達到了這個目標。
- 異步套接字
- 與工廠模式結合的快速XML解析器
- 自有的輕量級XML Dom,作爲所有agsXMPP協議類的基礎
我們爲什麼不直接所用Microsoft的System.Xml命名空間裏的類呢?
因爲我們決定創建自己的輕量級的Xml Dom,能夠飛快地運作,特別是在像PPC's和Smartphones這樣的嵌入式設備上。
XmlTextReader有利於SAX-like的解析。但是Microsoft在.NET1.1的SP1中做了下改變,這使得我們不能夠再使用它來解析網絡流。所以我們需要另外的XML解析器。
類庫的驚人之處在哪?
一旦從套接字接收到數據,該數據便由sax-like XML解析器解析。此解析器使用工廠模式來創建agsXMPP協議類相關的元素。
示例:
套接字接收到一條信息,將比特流推送至解析器。XML解析器探測到隸屬於jabber:client命名空間中名字爲message的開標籤符。在元素創建前,解析器在工廠散列表中做個查找。這樣就創建了agsXMPP.protocol.client.Message類的一個實例。如果表中不存在name/namespace的綁定,則會創建agsXMPP.Xml.Element的一個實例。
所有的XMPP協議類都派生自agsXMPP.Xml.Element。他們都是在內存中保持XML樹的'abstract'元素。所有的屬性都是'realtime properties'。在我們要讀取消息體,調用消息體屬性時,類將會實時查找<body/>元素。
Creating your own packet types
下面的小例子中我們將要創建一個我們自己的擴展,通過XMPP網絡發送天氣信息。最簡單的方法是將天氣的數據信息嵌入到一個message節中。嵌入了天氣信息的新XML message如下所示:
<weather xmlns="agsoftware:weather">
<humidity>90</humidity>
<temperature>57</temperature>
</weather>
</message>
我們要給這個新的協議創建一個新的命名空間和3個新元素:weather、humidity和temperature
首先,我們給我們定製的XML元素創建一個新的類weather.cs,派生自agsXMPP.Xml.Dom.Element。
using agsXMPP.Xml.Dom;
namespace MiniClient
{
public class Weather : Element
{
public Weather()
{
this.TagName = "weather";
this.Namespace = "agsoftware:weather";
}
public Weather(int humidity, int temperature) : this()
{
this.Humidity = humidity;
this.Temperature = temperature;
}
public int Humidity
{
get { return GetTagInt("humidity"); }
set { SetTag("humidity", value.ToString()); }
}
public int Temperature
{
get { return GetTagInt("temperature"); }
set { SetTag("temperature", value.ToString()); }
}
}
}
然後在元素工廠中註冊這個新類。如果不註冊,在解析XML流時XML解析器就不會weather對象。我們通過下面的代碼註冊該類:
"agsoftware:weather", typeof(Weather));
我們在使用agsXMPP處理其它事件時,應該先註冊我們自己的元素。
現在我們能夠創建自己的weather message,然後發送:
Jid to = new Jid("[email protected]");
Message msg = new Message();
msg.To = to;
// Add our weather Element
msg.AddChild(weather);
// Send the message
XmppCon.Send(msg);
接收此message的另一個應用程序可以像OnMessage handler那樣訪問到我們的定製數據:
{
if (msg.HasTag(typeof(Weather)))
{
Weather weather = msg.SelectSingleElement(typeof(Weather)) as Weather;
Console.WriteLine(weather.Temperature.ToString());
Console.WriteLine(weather.Humidity.ToString());
}
}
現在我們創建了我們第一個自己的(信息)包,包含了一個message節。接下去我們要創建基於Iqs的小型weather service。
service的raw xml protocol:
Romeo向weather service請求了他城市的天氣信息,zip code爲'74080':
<query xmlns='agsoftware:weather'>
<zip>74080</zip>
</query>
</iq>
接着weather service查找該zip code的天氣數據,然後返回結果給Romeo:
<query xmlns='agsoftware:weather'>
<humidity>90</humidity >
<temperature>57</temperature>
<zip>74080</zip>
</query>
</iq>
Weather.cs的源代碼:
using agsXMPP.Xml;
using agsXMPP.Xml.Dom;
public class Weather : Element
{
public Weather()
{
this.TagName = "query";
this.Namespace = "agsoftware:weather";
}
public int Humidity
{
get { return GetTagInt("humidity"); }
set { SetTag("humidity", value.ToString()); }
}
public int Temperature
{
get { return GetTagInt("temperature"); }
set { SetTag("temperature", value.ToString()); }
}
public int Zip
{
get { return GetTagInt("zip"); }
set { SetTag("zip", value.ToString()); }
}
}
WeatherIq.cs的源代碼:
using agsXMPP;
using agsXMPP.protocol.client;
public class WeatherIq : IQ
{
private Weather m_Weather = new Weather();
public WeatherIq()
{
base.Query = m_Weather;
this.GenerateId();
}
public WeatherIq(IqType type)
: this()
{
this.Type = type;
}
public WeatherIq(IqType type, Jid to)
: this(type)
{
this.To = to;
}
public WeatherIq(IqType type, Jid to, Jid from)
: this(type, to)
{
this.From = from;
}
public new Weather Query
{
get
{
return m_Weather;
}
}
}
當然我們要在工廠裏註冊Weather對象,使用下面代碼:
"agsoftware:weather", typeof(Weather));
Romeo的客戶端使用WeatherIq對象創建了請求Iq包:
wIq.To = new Jid("weather.mortagne.net");
wIq.From = new Jid("[email protected]");
wIq.Query.zip = 74080;
// Send the message
XmppCon.Send(wIq);
weather service在Iq handler中接收此請求,然後把響應發回給Romeo。在weather service中獲得請求信息,然後編輯:
{
IQ iq = e as IQ;
Element query = iq.Query;
if (query != null)
{
if (query.GetType() == typeof(Weather))
{
// its a Weather IQ
Weather weather = query as Weather;
if (iq.Type == IqType.get)
{
Console.WriteLine(weather.Zip.ToString());
// read the zip code and lookup the weather
// data for this zip code
// . . . .
iq.SwitchDirection();
iq.Type = IqType.result;
weather.Humidity = 90;
weather.Temperature = 57;
// Send the result back to romeo
XmppCon.Send(iq);
}
}
}
}
Romeo接收到響應,然後通過我們的weather對象的屬性訪問到天氣數據。
http://www.cnblogs.com/HappyQQ/archive/2008/01/13/1036646.html