C#連接基於Java開發IM——Openfire

来源:https://www.cnblogs.com/WarrenRyan/archive/2019/02/20/10406535.html
-Advertisement-
Play Games

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.dllXmppClientConnection 類進行連接,就算你代碼毫無錯誤,也無法正常連接Openfire,因為
博主只是對源碼改了一句話,即可正常連接。
修改 protocolsasl 下的 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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現在好些網站都支持掃碼登錄,感覺上安全了很多,但是本地程式掃碼登錄的不多,就用C 實現了一下,需要作如下準備 1. 在官網上申請一個企業微信,有條件的話做個企業認證吧,我們的是認證過的,所以賬號和本地其他系統的賬號是統一的. 2. 在應用中創建一個應用,這個是關鍵,我們掃碼就是和它有關. 3. 點擊 ...
  • 0 綜述 1 MVP各模塊規範 1.1 實體模塊規範 1.1.1 命名規範 實體類封裝到單獨的DLL中,DLL命名遵循<ProjectName>.DataEntity。資料庫實體類名遵循:資料庫表名去掉複數尾碼,如“s”、“es”等(資料庫表的名稱必須是名詞複數)。 1.1.2 架構規範 實體模塊中 ...
  • 成功的故事固然蕩氣迴腸,失敗的故事也能千迴百轉,但是如果你連第一步都不願邁出,不去追求與償試,那麼你永完不會知道成功或者失敗的原因是什麼,人生一輩子也就三萬多天,如果每天糊裡糊塗的過去了,若幹年後可能連故事都沒得講。 年前的時候廣州.net俱樂部主席葉老師就曾微信找我私聊,說你可以在合肥組織一個合肥 ...
  • ASP.net core 使用UEditor.Core 實現 ueditor 上傳功能 首先通過nuget 引用UEditor.Core,作者github:https://github.com/baiyunchen/UEditor.Core/ 在Startup.cs中添加 引入ueditor並配置 ...
  • 一. 支持欄位 EF允許讀取或寫入欄位而不是一個屬性。在使用實體類時,用面向對象的封裝來限制或增強應用程式代碼對數據訪問的語義時,這可能很有用。無法使用數據註釋配置。除了約定,還可以使用Fluent API為屬性配置支持欄位。 1.1 約定 1.2 Fluent API 二. 構造函數 從開始 EF ...
  • 1.對微服務的理解 之前看到在群里的朋友門都在討論微服務,看到他們的討論,我也有了一些自己的理解,所謂微服務就是系統里的每個服務都 可以自由組合。自由組合這個就很厲害了,這樣一來,每個服務與服務之間基本的物理 耦合為0,橫向擴展整個系統就會非常非常靈活。 surging的厲害之處也恰恰是可以做到這些 ...
  • 鏈接:https://pan.baidu.com/s/1SJHKTvQ4av_P9kLrtyYZ6w 提取碼:toya ...
  • 右鍵“工具箱”選擇“選擇項” 彈出對話框 選擇“瀏覽” 選中下載還的dll庫文件。完成後工具箱中會有 treeGridView控制項,如下圖 拖動控制項到windform 中 添加代碼 參考: https://www.cnblogs.com/mrtiny/p/5174095.html ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...