欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#连接基于Java开发IM——Openfire

程序员文章站 2022-11-18 08:03:00
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("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

欢迎关注我的博客获得第一时间更新

我的github:steveneco

我的博客园:warrenryan