当前位置: 移动技术网 > IT编程>开发语言>.net > C#连接基于Java开发IM——Openfire

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

2019年02月21日  | 移动技术网IT编程  | 我要评论

49岁陈红拒粉丝礼物,南岸区人力资源和社会保障网,天门南站

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网