XMPP
简单说XMPP是由IETF制定的一个可扩展的即时消息通信协议。XMPP基本有两部分组成,一部分是它的核心协议,还有一部分是扩展协议。
其中核心协议主要由RFC-6120、RFC-6121、RFC-6122组成。
还有一堆的扩展协议,具体可以参见XMPP官网扩展协议列表部分。一般会使用到得扩展协议包括XEP-0160 XEP-0013离线消息处理、xep-0045多用户聊天、XEP-0096文件传输
XMPP具有的一些基本性质如下:
基于XML
标准
可扩展
Ejabberd
Ejabberd(Erlang)可以说是最棒的XMPP Server了吧,另外Openfire(Java)也是一个比较不错的XMPP Server实现。个人虽然是Java开发者,但还是更倾向于使用Erlang开发的Ejabberd,原因是Erlang自身具备的容错性和强大的无痛水平扩展能力确实比Java要高明很多。同时Ejabberd的安装和使用都非常爽快,属于是开箱即用类型的,而且文档也很齐全。
安装采用的是傻瓜式的安装,非源码安装。
1、Ejabberd的开发语言是Erlang,首先安装Erlang。
apt-get install erlang
2、安装Ejabberd
apt-get install ejabberd
3、启动一个ejabberd实例
ejabberdctl start
配置和管理
当你启动一个ejabberd实例后,事实上你就可以直接用了,当然如果你需要深入的使用一些特性,还是需要做一些简单的配置的。
ejabberd默认的配置文件在/etc/ejabberd/ejabberd.cfg。
有一些配置在配置文件中被注释了的,Erlang是用百分号%作为注释语法,如果要使用这个配置删除%号就可以了。
另外erlang提供了一个web管理界面,首先先通过下面的这条命令注册一个XMPP管理账号。
ejabberdctl register user host password
如果使用默认的端口配置的话就可以用这个链接http://server:5280/admin/登录到web管理控制台了。
Smack
Smack是Java语言写的XMPP Library,个人观察下来貌似也是Java下最好得XMPP客户端了。下面演示一下实际IM场景中最基本的几个需求用Smack怎么来实现。
链接与登录
localhost 也就是Ejabberd的服务的域名
ConnectionConfiguration config = new ConnectionConfiguration("192.168.16.16", 5222, "localhost");
connection = new XMPPConnection(config);
connection.connect();
connection.login("zhuxiaohao", "123456", "zhuxiaohao");
登录后可以在web管理界面中看到用户在线得状态,前提是与Ejabberd的连接不能断,比如你就不能紧接着运行disconnect()了,这个和数据库之类的连接比起来是一个很大的差别,原因是XMPP协议本身就是长连接的。
可以通过setSendPresence(boolean sendPresence)来控制隐身登录。
聊天
ChatManager chatmanager = connection.getChatManager();
Chat newChat = chatmanager.createChat("chenhao@localhost", new MessageListener() {
public void processMessage(Chat chat, Message message) {
System.out.println("Received message: " + message);
}
});
try {
newChat.sendMessage("hello!");
}
catch (XMPPException e) {
System.out.println("Error 连接失败");
}
接收
connection.getChatManager().addChatListener(new ChatManagerListener() {
@Override
public void chatCreated(Chat chat, boolean createdLocally) {
chat.addMessageListener(new MessageListener() {
@Override
public void processMessage(Chat chat, Message message) {
System.out.println(message.getBody());
}
});
}
});
离线消息处理
下面的这种处理方式可以用于在线状态登录时离线消息的接收,如果需要在离线状态也可以接收到离线消息时,可以用OfflineMessageManager来控制,但是需要注意,比较坑爹的是Ejabberd的Community Server版本并不支持XEP-0013Flexible Offline Message Retrieval 这个协议,所以OfflineMessageManager也就用不了啦。
好在Smack在很多协议API中都有关于服务端是否支持此协议的API。比如下面这种
public boolean supportsFlexibleRetrieval()
ConnectionConfiguration config = new ConnectionConfiguration("192.168.16.16", 5222, "localhost");
config.setSendPresence(true);
Connection conn = new XMPPConnection(config);
conn.connect();
conn.addPacketListener(new PacketListener() {
@Override
public void processPacket(Packet packet) {
DelayInformation delay = (DelayInformation)packet.getExtension("x", "jabber:x:delay");
if(delay == null) {
return;
}
if(packet instanceof Message) {
System.out.println(((Message)packet).getBody());
}
}
}, null);
conn.login("zhuxiaohao", "123456", "zhuxiaohao");
发送文件
发送
FileTransferManager fileTransferManager = new FileTransferManager(connection);
// Create the outgoing file transfer
OutgoingFileTransfer transfer = fileTransferManager.createOutgoingFileTransfer("mahaiyue@localhost/test");
// Send the file
transfer.sendFile(new File(TestMessaging.class.getResource("origin").toURI()), "You won't believe this!");
Thread.sleep(5000);
System.out.println(transfer.getException());
System.out.println(transfer.getProgress());
System.out.println(transfer.isDone());
接收
manager.addFileTransferListener(new FileTransferListener() {
public void fileTransferRequest(FileTransferRequest request) {
// Check to see if the request should be accepted
if(shouldAccept(request)) {
// Accept it
IncomingFileTransfer transfer = request.accept();
try {
transfer.recieveFile(new File("test.java"));
}
catch (XMPPException e) {
e.printStackTrace();
}
} else {
// Reject it
request.reject();
}
}
private boolean shouldAccept(FileTransferRequest request) {
System.out.println(request.getMimeType());
return true;
}
});
有没有觉得很简单,打造属于自己的 IM聊天工具.感觉有木有很流弊.一系列文章小生会陆续写出来,晚上回去加班写代码,白天要上班,时间有限.所以出的慢点了.