Openfire 是開源的、基於可拓展通信和表示協議(XMPP)、採用Java編程語言開發的實時協做服務器。Openfire的效率很高,單臺服務器可支持上萬併發用戶。
Server和Client端的通訊都用xml文檔的形式進行通訊。
可是Openfire是Java語言寫的,對於C#的dll拓展庫相比與java的jar包少的可憐,在網上尋找一番以後找到了一個比較好的dll拓展庫,agsxmpp是一個專門爲C#鏈接xmpp協議下即時通信已經搭建xmpp協議服務端的的dll,同時他有商業版MatriX,博主窮學生一個,沒有啥錢去購買商業版,仍是採用了普通的agsxmpp。java
agsxmpp是AG—Software進行開發的一個開源項目,能夠在它的官網進行下載源碼。
agsxmpp是在2003年開始研發,2008年發佈它的最後一個版本,所以它在兼容性上顯然是不很好的。
同時在C#鏈接Openfire上,agsxmpp中有一個巨坑,加上網上關於agsxmpp的開發文檔奇少,並且博主沒有在官網上找到相關的開發文檔(就算有也是全英文看不懂系列),故記下開發全過程。
由於agsxmpp並非專門爲Openfire製做的,而是對任何以xmpp協議的即時通信進行鏈接等服務。若是不對源碼進行必定的重寫,在某些狀況下會出現一些問題。
若是你直接使用 agsxmpp.dll 中 XmppClientConnection 類進行鏈接,就算你代碼毫無錯誤,也沒法正常鏈接Openfire,由於
博主只是對源碼改了一句話,便可正常鏈接。
修改 protocol 中 sasl 下的 Mechanism.cs 中源碼,將git
case "DIGEST-MD5": return MechanismType.DIGEST_MD5;
註釋,由於 openfire 發送數據流 是經過 PLAIN 的 , 而 agsxmpp 是默認是 經過DIGEST-MD5 發送。
同時,在agsxmpp中,還有一個地方表現了對openfire的不兼容,openfire 發送iq節 不接收 to屬性,所以還須要修改一個地方
源代碼以下github
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() 方法編程
官方提供了一個只有三行代碼的小型Democ#
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("testa@118.89.48.159", 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