Openfire簡介 Openfire 是開源的、基於可拓展通訊和表示協議(XMPP)、採用Java編程語言開發的實時協作伺服器。Openfire的效率很高,單台伺服器可支持上萬併發用戶。 Server和Client端的通信都用xml文檔的形式進行通 ...
Openfire簡介
Openfire 是開源的、基於可拓展通訊和表示協議(XMPP)、採用Java編程語言開發的實時協作伺服器。Openfire的效率很高,單台伺服器可支持上萬併發用戶。
Server和Client端的通信都用xml文檔的形式進行通信。
但是Openfire是Java語言寫的,對於C#的dll拓展庫相比與java的jar包少的可憐,在網上尋找一番之後找到了一個比較好的dll拓展庫,agsxmpp是一個專門為C#連接xmpp協議下即時通訊已經搭建xmpp協議服務端的的dll,同時他有商業版MatriX,博主窮學生一個,沒有啥錢去購買商業版,還是採用了普通的agsxmpp。
AgsXmpp簡介
agsxmpp是AG—Software進行開發的一個開源項目,可以在它的官網進行下載源碼。
agsxmpp是在2003年開始研發,2008年發佈它的最後一個版本,因此它在相容性上顯然是不很好的。
同時在C#連接Openfire上,agsxmpp中有一個巨坑,加上網上關於agsxmpp的開發文檔奇少,而且博主沒有在官網上找到相關的開發文檔(就算有也是全英文看不懂系列),故記下開發全過程。
因為agsxmpp並不是專門為Openfire製作的,而是對任何以xmpp協議的即時通訊進行連接等服務。如果不對源碼進行一定的重寫,在某些情況下會出現一些問題。
如果你直接使用 agsxmpp.dll 中 XmppClientConnection 類進行連接,就算你代碼毫無錯誤,也無法正常連接Openfire,因為
博主只是對源碼改了一句話,即可正常連接。
修改 protocol 中 sasl 下的 Mechanism.cs 中源碼,將
case "DIGEST-MD5":
return MechanismType.DIGEST_MD5;
註釋,因為 openfire 發送數據流 是通過 PLAIN 的 , 而 agsxmpp 是預設是 通過DIGEST-MD5 發送。
同時,在agsxmpp中,還有一個地方表現了對openfire的不相容,openfire 發送iq節 不接收 to屬性,因此還需要修改一個地方
源代碼如下
public IQ SendIq(agsXMPP.protocol.client.IQ iq, int timeout)
{
synchronousResponse = null;
AutoResetEvent are = new AutoResetEvent(false);
SendIq(iq, new IqCB(SynchronousIqResult), are);
if (!are.WaitOne(timeout, true))
{
// Timed out
lock (m_grabbing)
{
if (m_grabbing.ContainsKey(iq.Id))
m_grabbing.Remove(iq.Id);
}
return null;
}
return synchronousResponse;
}
修改後如下
public void SendIq(IQ iq, IqCB cb, object cbArg)
{
// check if the callback is null, in case of wrong usage of this class
if (cb != null)
{
TrackerData td = new TrackerData();
td.cb = cb;
td.data = cbArg;
m_grabbing[iq.Id] = td;
//iq在agsxmpp中發送Iq節的時候先iq.RemoveAttribute("to")
iq.RemoveAttribute("to");
}
m_connection.Send(iq);
}
public void SendIq2(IQ iq, IqCB cb, object cbArg)
{
// check if the callback is null, in case of wrong usage of this class
if (cb != null)
{
TrackerData td = new TrackerData();
td.cb = cb;
td.data = cbArg;
m_grabbing[iq.Id] = td;
//iq在agsxmpp中發送Iq節的時候先iq.RemoveAttribute("to")
//iq.RemoveAttribute("to");
}
m_connection.Send(iq);
}
登錄操作:發送xml消息用 SendIq() 方法
其他操作:發送xml消息用 SendIq2() 方法
連接上Openfire
官方提供了一個只有三行代碼的小型Demo
XmppClientConnection xmpp = new XmppClientConnection(server);
xmpp.Open(username,secret);
xmpp.OnLogin+=delegate(object o){xmpp.Send(new Message(JID,MessageType.chat,msg));};
我的代碼
public class XmppLogin
{
private XmppClientConnection xmppCon;
private bool isSSL;
/// <summary>
/// 是否使用加密連接
/// </summary>
public bool IsSSL { get { return isSSL; } set { isSSL = value; } }
private string userName;
private string server;
public string Server { get { return server; } set { server = value; } }
/// <summary>
/// 用戶名
/// </summary>
public string UserName { get { return userName; } set { userName = value; } }
private string passWord;
/// <summary>
/// 密碼
/// </summary>
public string PassWord { get { return passWord; } set { passWord = value; } }
private string clientVersion;
/// <summary>
/// 客戶端版本
/// </summary>
public string ClientVersion { get { return clientVersion; }set { clientVersion = value; } }
/// <summary>
/// 登錄狀態
/// </summary>
public string LoginState { get { return xmppCon.XmppConnectionState.ToString(); } }
private int port;
/// <summary>
/// 登錄埠,通常是5222,加密時是5223
/// </summary>
public int Port { get { return port; }set{ port = value;} }
public XmppLogin()
{
xmppCon = new XmppClientConnection();
}
#region 傳遞一個XmppClient對象
/// <summary>
/// 傳遞一個XmppClient對象
/// </summary>
/// <param name="con">需要操作的具體實例</param>
public XmppLogin(XmppClientConnection con)
{
xmppCon = new XmppClientConnection();
xmppCon = con;
}
#endregion
#region 登錄
/// <summary>
/// 登錄openfire的方法
/// </summary>
/// <returns>返回值為是否登錄</returns>
public void Login()
{
xmppCon.Server = server;
xmppCon.UseSSL = false;
xmppCon.Port = 5222;
xmppCon.AutoResolveConnectServer = true;
xmppCon.UseCompression = false;
xmppCon.EnableCapabilities = true;
xmppCon.ClientVersion = "1.0";
xmppCon.Capabilities.Node = "http://www.ag-software.de/miniclient/caps";
xmppCon.DiscoInfo.AddIdentity(new DiscoIdentity("pc", "MyClient", "client"));
xmppCon.DiscoInfo.AddFeature(new DiscoFeature(agsXMPP.Uri.DISCO_INFO));
xmppCon.DiscoInfo.AddFeature(new DiscoFeature(agsXMPP.Uri.DISCO_ITEMS));
xmppCon.DiscoInfo.AddFeature(new DiscoFeature(agsXMPP.Uri.MUC));
xmppCon.Open(userName,passWord);
//xmppCon.OnLogin += delegate (object o) { xmppCon.Send(new agsXMPP.protocol.client.Message("[email protected]", MessageType.chat, "sdgo")); };
}
#endregion
#region 測試連接
/// <summary>
/// 測試指定的OpenFire伺服器和埠是否能連通
/// </summary>
/// <returns>返回是否能連通</returns>
public bool TestPing()
{
string ipAddress = Server;
int portNum = port;
bool CanConnect = false;
IPAddress ip = IPAddress.Parse(ipAddress);
try
{
IPEndPoint point = new IPEndPoint(ip, portNum);
using (Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
sock.Connect(point);
CanConnect = sock.Connected;
sock.Close();
return CanConnect;
}
}
catch (SocketException e)
{
//LOG TODO
return false;
}
}
#endregion
public static implicit operator XmppClientConnection(XmppLogin v)
{
return v.xmppCon;
}
}
至此,Openfire連接成功。
最近忙而且也剛開始弄這個,過幾天更新一下XmppConnection下各種屬性、事件、函數的具體用法。
我的掘金:WarrenRyan
我的簡書:WarrenRyan
歡迎關註我的博客獲得第一時間更新 https://blog.tity.online
我的Github:StevenEco
我的博客園:WarrenRyan