Openfire 是开源的、基于可拓展通信和表示协议(XMPP)、采用Java编程语言开发的实时协做服务器。Openfire的效率很高,单台服务器可支持上万并发用户。 Server和Client端的通讯都用xml文档的形式进行通讯。 可是Openfire是Java语言写的,对于C#的dll拓展库相比与java的jar包少的可怜,在网上寻找一番以后找到了一个比较好的dll拓展库,agsxmpp是一个专门为C#链接xmpp协议下即时通信已经搭建xmpp协议服务端的的dll,同时他有商业版MatriX,博主穷学生一个,没有啥钱去购买商业版,仍是采用了普通的agsxmpp。java
AgsXmpp简介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() 方法编程
链接上Openfire官方提供了一个只有三行代码的小型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; /// /// 是否使用加密链接 /// public bool IsSSL { get { return isSSL; } set { isSSL = value; } } private string userName; private string server; public string Server { get { return server; } set { server = value; } } /// /// 用户名 /// public string UserName { get { return userName; } set { userName = value; } } private string passWord; /// /// 密码 /// public string PassWord { get { return passWord; } set { passWord = value; } } private string clientVersion; /// /// 客户端版本 /// public string ClientVersion { get { return clientVersion; }set { clientVersion = value; } } /// /// 登陆状态 /// public string LoginState { get { return xmppCon.XmppConnectionState.ToString(); } } private int port; /// /// 登陆端口,一般是5222,加密时是5223 /// public int Port { get { return port; }set{ port = value;} } public XmppLogin() { xmppCon = new XmppClientConnection(); } #region 传递一个XmppClient对象 /// /// 传递一个XmppClient对象 /// /// 须要操做的具体实例 public XmppLogin(XmppClientConnection con) { xmppCon = new XmppClientConnection(); xmppCon = con; } #endregion #region 登陆 /// /// 登陆openfire的方法 /// /// 返回值为是否登陆 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 测试链接 /// /// 测试指定的OpenFire服务器和端口是否能连通 /// /// 返回是否能连通 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; } }