XMPP是基于XML的即时通信协议。对即时通信场景进行了高度抽象,好比用订阅对方的上下线状态表示好友。提供了文本通信、用户上下线通知、联系人管理、群组聊天等功能,还能够安装插件或自行拓展。java
服务端通常用OpenFire。git
以macOS为例,官网直接下载安装包,安装完成后,在系统菜单中打开OpenFire控制台,进入OpenFire的Web后台,走完配置向导。数据库能够用OpenFire自带的嵌入式数据库,也能够配置为MySQL。若是是局域网测试的话,主机名最好设置成内网IP。最后一步须要设置管理员密码,管理员的帐号是admin。配置完成后,能够登陆OpenFire的管理后台。github
OpenFire服务器默认开放用户注册、开放建群,因此能够无论OpenFire后台,直接拿来使用。数据库
大多XMPP客户端不提供用户注册功能,因此最好在OpenFire后台直接添加用户。试了多个客户端,只有Psi能够成功注册用户,并且登陆以后找不到退出的地方,也找不到建立用户的地方。安全
XMPP的图形客户端特别多,可是一个比一个难用。在macOS上勉强可使用的主要有Spark、Adium和Thunderbird。Spark是OpenFire官方提供的客户端,在使用时要注意禁用安全选项,若是主机不受信任的话。服务器
命令行下的客户端,可使用Profanitytcp
登陆XMPP帐户,须要服务器、用户名、密码三个字段。若是客户端没有提供单独的服务器输入框的话,用户名改用用户名@服务器
测试
Profanity不提供用户注册功能,须要先在后台添加用户,或者用其余客户端注册。ui
/connect 用户名@服务器 tls disable
/disconnect
/msg 用户名@服务器/用户昵称 文本
Alt/Option+数字
Alt+1是系统窗口,其余是聊天窗口/roster add 用户名@服务器
/sub request 用户名@服务器
/sub allow 用户名@服务器
/join 房间名@服务器
/away
=离开 /online
=在线 /dnd
=忙碌 .../quit
Smack是OpenFire提供的支持XMPP协议的Java接口.net
package bj; import io.vavr.control.Try; import lombok.extern.slf4j.Slf4j; import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.ConnectionConfiguration; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.roster.Roster; import org.jivesoftware.smack.roster.RosterEntry; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; import org.junit.Test; import org.jxmpp.jid.impl.JidCreate; import java.io.IOException; import java.net.InetAddress; import java.util.Set; /** * Created by BaiJiFeiLong@gmail.com at 2018/11/22 下午4:33 */ @Slf4j public class BazTest { @Test public void testAlpha() throws IOException, InterruptedException, XMPPException, SmackException { // 建立链接,并链接到服务器 AbstractXMPPConnection connection = new XMPPTCPConnection(XMPPTCPConnectionConfiguration.builder() .setUsernameAndPassword("gamma", "gamma") .setXmppDomain("172.16.5.254") .setHostAddress(InetAddress.getByName("172.16.5.254")) // 服务器地址直接用IP的话,不能用setHost() .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled) // 禁用安全模式,若是服务器不受信任 .build()).connect(); connection.login(); // 监听XMPP包(包括PING、在线状态、聊天消息等) connection.addSyncStanzaListener(packet -> log.info("[SyncStanzaListener] Packet received {}", packet), stanza -> true); // 只监听聊天消息 ChatManager.getInstanceFor(connection).addIncomingListener((entityBareJid, message, chat) -> { System.out.println(String.format("[IncomingListener] Message received %s : %s", entityBareJid, message.getBody())); // Echo此消息 Try.run(() -> chat.send(message.getBody())); System.out.println(Roster.getInstanceFor(connection).getEntries()); }); // 发送消息 connection.sendStanza(new Message("theta@172.16.5.254", "MESSAGE_BY_CONNECTION")); // 发送消息 方式二 ChatManager.getInstanceFor(connection).chatWith(JidCreate.entityBareFrom("theta@172.16.5.254")).send("MESSAGE_BY_CHAT_MANAGER"); // 获取联系人集合 Thread.sleep(1000); // 等待联系人更新 Set<RosterEntry> entries = Roster.getInstanceFor(connection).getEntries(); log.info("Contacts: {} persons", entries.size()); entries.forEach(System.out::println); // 保持运行 Thread.currentThread().join(); } }
控制台日志
10:55:24.924 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received IQ Stanza (query jabber:iq:roster) [to=gamma@172.16.5.254/612m1g1ciz,id=gvsBl-5,type=result,] 10:55:24.933 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/1gwvh0rdvv,id=L85kQ-6,type=available,] 10:55:24.933 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/1pj92olp11,id=RamcN-7,type=available,] 10:55:24.933 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/8aadbwm30s,id=xkaYN-7,type=available,] 10:55:24.934 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/profanity,id=prof_presence_595,type=available,] 10:55:24.937 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/9trigmn7f2,id=SJ41s-7,type=available,] 10:55:24.937 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/42awvmq6te,id=iMJUx-6,type=available,] 10:55:24.937 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/92ijqtzgxi,id=9gG6o-7,type=available,] 10:55:24.937 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/494vwn454w,id=byYRm-7,type=available,] 10:55:24.938 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/4wurqkoj8y,id=3BnGN-7,type=available,] 10:55:24.939 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Presence Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=gamma@172.16.5.254/9vx8ve5vdm,id=YSZxk-6,type=available,] 10:55:25.939 [main] INFO bj.BazTest - Contacts: 3 persons : beta@172.16.5.254 : alpha@172.16.5.254 : theta@172.16.5.254 10:55:26.876 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Message Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=theta@172.16.5.254/profanity,id=prof_msg_670,type=chat,] [IncomingListener] Message received theta@172.16.5.254 : hello [: beta@172.16.5.254, : alpha@172.16.5.254, : theta@172.16.5.254] 10:55:28.839 [Smack Cached Executor] INFO bj.BazTest - [SyncStanzaListener] Packet received Message Stanza [to=gamma@172.16.5.254/612m1g1ciz,from=theta@172.16.5.254/profanity,id=prof_msg_671,type=chat,] [IncomingListener] Message received theta@172.16.5.254 : world [: beta@172.16.5.254, : alpha@172.16.5.254, : theta@172.16.5.254]