一、XMPP协议
XMPP (Extensible Messaging and Presence Protocol可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。XMPP的前身是Jabber,基于XMPP的应用具有很强的可扩展性。
1、XMPP中的几个重要概念:
JID:即Jabber ID。xmpp网络有一个或多个地址jid,如a@aaa.lit/study 。
组成:节点、域、资源(带有资源的jid是完整jid,没有资源的jid是裸jid),其中节点和资源是可选的,域是必选的。jid的资源部分会标识一个特定的客户端xmpp链接,对于xmpp客户端来说,每个链接均被指派一个资源。
XMPP中定义了三个角色,客户端,服务器,网关。
通信能够在这三者的任意两个之间双向发生。
服务器同时承担了客户端信息记录,连接管理和信息的路由功能。
网关承担着与异构即时通信系统的互联互通,异构系统可以包括SMS(短信),MSN,ICQ等。
客户端或服务器发送的所有XML文本连缀在一起,从<stream>到</stream>构成了一个完整的XML文档。
XML流:其中的stream标签就是所谓的XML Stream。
XML节:在<stream>与</stream>中间的那些<message>...</message>这样的XML元素就是所谓的XML Stanza
关于XMPP协议的一些细节,这里也只写了个大概。具体请参见“XMPP协议参考手册”,或查阅相关书籍。
2、XMPP工作原理:
(1)先建立一个stream,然后协商一堆安全之类的东西,中间通信过程就是客户端一个接一个的发送XML Stanza给服务器。
(2)服务器根据客户端发送的信息以及程序的逻辑,发送XML Stanza给客户端。(这个过程并不是一问一答的,任何时候都有可能从一方发信给另外一方。)
(3)通信的最后阶段</stream>关闭流,关闭TCP/IP连接。
XMPP 是一种很类似于http协议的一种数据传输协议,它的过程就如同“解包装--〉包装”的过程,用户只需要明白它接收的类型,并理解它返回的类型,就可以很好的利用xmpp来进行数据通讯。
关于XMPP的一些扩展协议:http://xmpp.org/xmpp-protocols/xmpp-extensions/
二、XMPP环境
1、服务器软件
服务器软件列表:http://xmpp.org/xmpp-software/servers/
用得最多的当是Openfire了。ejabberd也用的比较多。
关于Openfire的安装与配置,看下面的blog就可以了
http://blog.csdn.net/shimiso/article/details/8816558 Windows下
http://blog.csdn.net/jeepxiaozi/article/details/16357337 Mac下
2、客户端软件
客户端软件主要用来自己做开发测试时使用。
客户端软件列表:http://xmpp.org/xmpp-software/clients/
客户端使用Spark即可,登录时,先在服务器上多创建几个账号,然后直接登录其中一个,添加联系然即可进行聊天。
其他客户端软件参考Spark即可(最重要的是把JID输入正确)
参考下面文章:(仅供参考,没他写的那么复杂。第四步是另一回事,不用管)
http://www.cnblogs.com/top5/archive/2009/04/07/1431001.html
三、XMPP基础实践
1、iOS上用XMPP开发IM软件
XMPP开发即自己做客户端连接XMPP服务器,实现点对点,群聊等功能。这里只是做一些基本的操作,具体细节还需要根据软件的业务来做。
XMPPFramework:一个XMPP协议的OC实现。关于XMPPFramework的简介与使用,可以参考其github上官方wiki。
https://github.com/robbiehanson/XMPPFramework/wiki/IntroToFramework
1)XMPP Core
XMPPFramework分为2部分,其一为XMPP Core,另一部分为extensions,即XEP‘s扩展。
XMPP Core中的一些类:(大部分类可以顾名思义)
- XMPPStream
- XMPPParser
- XMPPJID
- XMPPElement
- XMPPIQ
- XMPPMessage
- XMPPPresence
- XMPPModule
- XMPPLogging
- XMPPInternal
2)XMPPStream
在XMPPFramework中,核心类即为XMPPStream,它是一个非常基础的类。下面英文简绍了其他一些类的作用。
The heart of the framework is the XMPPStream class. This is the primary class you will be interacting with, and it is the class that all extensions and custom code will plug into. It has a number of interesting features designed to make the framework flexible, extensible, and easy to develop on top of. These will be discussed in more depth later in this document.
The XMPPParser is an internal class used by XMPPStream. You can probably take a wild guess as to what it does. You will not need to interact with the parser in any way, shape, or form.
XMPPJID provides an immutable JID (Jabber Identifier) implementation. It supports parsing of JID's, and extracting various parts of the JID in various forms. It conforms to the NSCopying protocol so that JID's may be used as keys in NSDictionary. It even conforms to the NSCoding protocol.
XMPPElement is the base class for the 3 primary XMPP elements: XMPPIQ, XMPPMessage & XMPPPresence. XMPPElement extends NSXMLElement, so you have the entire NSXML foundation with which to inspect any xml element. This is discussed in more detail in the section Elements: IQ, Message, & Presence.
XMPPModule provides the foundation class for optional pluggable extensions. If you are writing your own application specific (proprietary) code, you will likely just create your own class and register to receive delegate invocations. However, if you are implementing a standard XEP, or you want your application specific extensions to be pluggable, then you'll be building atop XMPPModule. Modules are discussed in more detail below.
XMPPLogging provides a very fast, powerful and flexible logging framework. It is discussed in the XMPP Logging section.
XMPPInternal is just internal stuff related to the core and various advanced low-level extensions.
3)Elements: IQ, Message, & Presence (节点元素)
XMPPElement是继承自NSMXLElement的,继承关系如下。
XMPPIQ -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
XMPPMessage -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
XMPPPresence -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
框架同时提供了NSXMLElement+XMPP分类,使写起代码来更加清晰与好看。
[element attributeIntValueForName:@"age"];
4)XMPPStream配置与连接
可分为以下几个步骤:
①配置连接
xmppStream.myJID = [XMPPJID jidWithString:@"user@myCompany.com"];或者
xmppStream.hostName = @"myCompany.com";
xmppStream.myJID = [XMPPJID jidWithString:@"user@dev1.myCompany.com"];
xmppStream.hostName = @"192.168.2.27";
②添加代理(MulticastDelegate)
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
...
[xmppStream removeDelegate:self];
③添加组件(Modules)
可以添加以下组件(不限于)
XMPPReconnect - automatically reconnects the stream if you get accidentally disconnected.
XMPPRoster - provides support for standard xmpp roster.
XMPPRoom - provides multi-user chat support.
XMPPPubSub - Publish subscribe
以下代码添加XMPPReconnect组件到stream中
xmppReconnect = [ [XMPPReconnect alloc] init];
// Optional configuration of xmppReconnect could go here.
// The defaults are fine for our purposes.
[xmppReconnect activate:xmppStream];
// You can also optionally add delegates to the module.
[xmppReconnect addDelegate:self delegateQueue:dispatch_get_main_queue()];
// And that's all that is needed.
// The module will receive any delegate methods it needs automatically
// from the xmpp stream, and will continue to do its thing unless you deactivate it.
④连接
如果忘记设置属性,如JID,则会返回NO
NSError *error = nil;
if (![xmppStream connect:&error])
{
NSLog(@"Oops, I probably forgot something: %@", error);
}
⑤认证
当所有的连接握手结束后,xmppStreamDidConnect: 代理方法将会被调用,可在此处进行一些认证操作等。
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
[xmppStream authenticateWithPassword:password error:NULL];
}
XMPPFramework中给的iPhoneXMPP项目可作为参考,关于如何配置参见http://www.cnblogs.com/uvsjoh/archive/2012/08/11/2633306.html
https://github.com/funkyboy/Building-a-Jabber-client-for-iOS 好东西,不解释。
登录成功,上张图:(本机测试的话,注意在代码中配置host)
2、Android上用XMPP开发IM软件
Android中比iOS可参考的资料与源码更多。
几个基本概念:
Spark :提供了客户端一个基本的实现,并提出了一个很好的插件架构,这对于开发者来说不能不说是一个福音。我强烈建议基于插件方式来实现你新增加的功能,而不是去改它的源代码,这样有利于你项目架构,把原始项目的影响降到最低。
Openfire :是基于XMPP 协议的IM 的服务器端的一个实现,虽然当两个用户连接后,可以通过点对点的方式来发送消息,但是用户还是需要连接到服务器来获取一些连接信息和通信信息的,所以服务器端是必须要实现的。Openfire 也提供了一些基本功能,但真的很基本的!庆幸的是,它也提供插件的扩展,像Spark 一样。
Smack :是一个XMPP 协议的Java 实现,提供一套可扩展的API,不过有些时候,你还是不得不使用自己定制发送的XML 文件内容的方式来实现自己的功能。
XMPP协议的实现可能有很多,既然选择了使用Smack来做,那么自然看smack的文档来做是最好了。
1)Connect and Disconnect (连接)
// Create the configuration for this new connection_
ConnectionConfiguration config = new ConnectionConfiguration("jabber.org", 5222);
AbstractXMPPConnection connection = new XMPPTCPConnection(config);
// Connect to the server_
connection.connect();
// Log into the server_
connection.login("username", "password", "SomeResource");
...
// Disconnect from the server_
connection.disconnect();
By default Smack will try to reconnect the connection in case it was abruptly disconnected. Use ConnectionConfiguration#setReconnectionAllowed(boolean) to turn on/off this feature. The reconnection manager will try to immediately reconnect to the server and increase the delay between attempts as successive reconnections keep failing.
In case you want to force a reconnection while the reconnetion manager is waiting for the next reconnection, you can just use AbstractXMPPConnection#connect() and a new attempt will be made. If the manual attempt also failed then the reconnection manager will still continue the reconnection job.
(以上英文摘自smack文档。大意是:除非调用disconnect,默认情况下会重新连接,可以使用ConnectionConfiguration#setReconnectionAllowed(boolean)方法来关闭或者打开该特性。 重连管理器会立即重连,并增加延迟。如果想手动重新连接,使用AbstractXMPPConnection#connect() 方法,失败了还是会继续重连的)
2)Roster Entries (名册条目,即单个好友的实体标示)
每个用户被标示为一个Roster Entry,包含以下3部分。
- 一个XMPP地址,即JID。
- 用户的名字
-用户所属的组名
Roster roster = connection.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
for (RosterEntry entry : entries) {
System.out.println(entry);
}
3)Listening for Roster and Presence Changes (监听与显示改变)
Roster roster = con.getRoster();
roster.addRosterListener(new RosterListener() {
// Ignored events public void entriesAdded(Collection<String> addresses) {}
public void entriesDeleted(Collection<String> addresses) {}
public void entriesUpdated(Collection<String> addresses) {}
public void presenceChanged(Presence presence) {
System.out.println("Presence changed: " + presence.getFrom() + " " + presence);
}
});
// Create a packet filter to listen for new messages from a particular
// user. We use an AndFilter to combine two other filters._
PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class),
new FromContainsFilter("mary@jivesoftware.com"));
// Assume we've created a XMPPConnection name "connection".
// First, register a packet collector using the filter we created.
PacketCollector myCollector = connection.createPacketCollector(filter);
// Normally, you'd do something with the collector, like wait for new packets.
// Next, create a packet listener. We use an anonymous inner class for brevity.
PacketListener myListener = new PacketListener() {
**public** **void** processPacket(Packet packet) {
// Do something with the incoming packet here._
}
};
// Register the listener._
connection.addPacketListener(myListener, filter);
以上是一些基本的操作,需要引入jar包。
http://download.csdn.net/detail/sky_monkey/5820879 (Android小例子)
说明:
XmppTool是负责连接服务器的工具类;(自己测试的话修改ip,或者在host文件中进行映射也可以)
FormLogin负责登录;
FormCilent负责登录后接受聊天消息冰显示;
FormFiles传文件。
连接后得到ChatManager,然后通过JID与特定用户进行聊天会话。(源码中自己修改相应的JID)
参考:
http://www.igniterealtime.org/index.jsp smack官方文档
http://blog.csdn.net/shimiso/article/details/8816558 4篇XMPP Android系列
https://github.com/robbiehanson/XMPPFramework/wiki/GettingStarted_iOS XMPPFramework
https://github.com/robbiehanson/XMPPFramework/wiki/IntroToFramework XMPPFramework使用
http://www.cnblogs.com/uvsjoh/archive/2012/08/11/2633306.html XMPPFrame Demo使用注意
http://code4app.com/ios/xmpp-for-ios/521705756803fa7c32000006 iOS
http://www.cnblogs.com/PhenixWang/p/3275454.html XMPP iOS
http://blog.csdn.net/kangx6/article/details/7739828 4篇XMPP iOS系列
http://code4app.com/search/XMPP 几个源码
转载请注明出处:http://blog.csdn.net/xn4545945