admin管理员组

文章数量:1441347

XMPP Smack 客户端指南

XMPP 是一种丰富而复杂的即时消息协议。

在本教程中,我们将介绍 Smack,这是一个用 Java 编写的模块化和可移植的开源 XMPP 客户端,它为我们完成了大部分繁重的工作。

2. 依赖关系

Smack 被组织为几个模块以提供更大的灵活性,因此我们可以轻松包含所需的功能。

其中一些包括:

  • 基于 TCP 的 XMPP 模块
  • 支持 XMPP 标准基金会定义的许多扩展的模块
  • 旧版扩展支持
  • 要调试的模块

我们可以在 XMPP 的文档中找到所有支持的模块。

但是,在本教程中,我们将只使用 tcpimextensionsjava7 模块:

代码语言:javascript代码运行次数:0运行复制
<dependency>
    <groupId>org.igniterealtime.smack</groupId>
    <artifactId>smack-tcp</artifactId>
</dependency>
<dependency>
    <groupId>org.igniterealtime.smack</groupId>
    <artifactId>smack-im</artifactId>
</dependency>
<dependency>
    <groupId>org.igniterealtime.smack</groupId>
    <artifactId>smack-extensions</artifactId>
</dependency>
<dependency>
    <groupId>org.igniterealtime.smack</groupId>
    <artifactId>smack-java7</artifactId>
</dependency>

最新版本可以在Maven Central找到。

3. 设置

为了测试客户端,我们需要一个 XMPP 服务器。为此,我们将在 jabber.hot-chilli 上创建一个帐户,这是一个免费的Jabber / XMPP服务。

之后,我们可以使用 XMPPTCPConnectionConfiguration 类配置 Smack,该类提供了一个构建器来设置连接的参数:

代码语言:javascript代码运行次数:0运行复制
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
  .setUsernameAndPassword("baeldung","baeldung")
  .setXmppDomain("jabb3r")
  .setHost("jabb3r")
  .build();

构建器允许我们设置执行连接所需的基本信息。如果需要,我们还可以设置其他参数,例如端口、SSL 协议和超时。

4. 连接

建立连接只需使用 XMPPTCPConnection 类即可实现:

代码语言:javascript代码运行次数:0运行复制
AbstractXMPPConnection connection = new XMPPTCPConnection(config);
connection.connect(); //Establishes a connection to the server
connection.login(); //Logs in

该类包含一个构造函数,该构造函数接受以前生成的配置。它还提供了连接到服务器和登录的方法。

建立连接后,我们可以使用Smack的功能,例如聊天,我们将在下一节中介绍。

如果连接突然中断,默认情况下,Smack 将尝试重新连接。

重新连接管理器将尝试立即重新连接到服务器,并增加尝试之间的延迟,因为连续的重新连接不断失败。

5. 聊天

该库的主要功能之一是–聊天支持。

使用 Chat 类可以在两个用户之间创建新的消息线程:

代码语言:javascript代码运行次数:0运行复制
ChatManager chatManager = ChatManager.getInstanceFor(connection);
EntityBareJid jid = JidCreate.entityBareFrom("baeldung2@jabb3r");
Chat chat = chatManager.chatWith(jid);

请注意,为了构建聊天,我们使用了ChatManager,并且显然指定了与谁聊天。我们通过使用 EntityBareJid 对象实现了后者,该对象包装了一个由本地部分 (baeldung2) 和域部分 (jabb3r) 组成的 XMPP 地址(又名 JID)。

之后,我们可以使用 send() 方法发送消息:

代码语言:javascript代码运行次数:0运行复制
chat.send("Hello!");

并通过设置侦听器接收消息:

代码语言:javascript代码运行次数:0运行复制
chatManager.addIncomingListener(new IncomingChatMessageListener() {
  @Override
  public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
      System.out.println("New message from " + from + ": " + message.getBody());
  }
});

5.1. 房间

除了端到端的用户聊天外,Smack 还通过使用房间为群聊提供支持。

有两种类型的房间,即时房间和预订房间。

即时会议室可立即访问,并根据某些默认配置自动创建。另一方面,在允许任何人进入之前,房间所有者会手动配置预订的房间。

让我们来看看如何使用多用户聊天管理器创建即时房间:

代码语言:javascript代码运行次数:0运行复制
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
MultiUserChat muc = manager.getMultiUserChat(jid);
Resourcepart room = Resourcepart.from("baeldung_room");
muc.create(room).makeInstant();

以类似的方式,我们可以创建一个预留房间:

代码语言:javascript代码运行次数:0运行复制
Set<Jid> owners = JidUtil.jidSetFrom(
  new String[] { "baeldung@jabb3r", "baeldung2@jabb3r" });

muc.create(room)
  .getConfigFormManger()
  .setRoomOwners(owners)
  .submitConfigurationForm();

6. 名册

Smack提供的另一个功能是可以跟踪其他用户的存在。

使用 Roster.getInstanceFor(),我们可以获取一个 Roster 实例:

代码语言:javascript代码运行次数:0运行复制
Roster roster = Roster.getInstanceFor(connection);

花名册是一个联系人列表,它将用户表示为名册条目对象,并允许我们将用户组织成组。

我们可以使用 getEntries() 方法打印花名册中的所有条目:

代码语言:javascript代码运行次数:0运行复制
Collection<RosterEntry> entries = roster.getEntries();
for (RosterEntry entry : entries) {
    System.out.println(entry);
}

此外,它允许我们使用 RosterListener 侦听其条目和状态数据的变化:

代码语言:javascript代码运行次数:0运行复制
roster.addRosterListener(new RosterListener() {
    public void entriesAdded(Collection<String> addresses) { // handle new entries }
    public void entriesDeleted(Collection<String> addresses) { // handle deleted entries }
    public void entriesUpdated(Collection<String> addresses) { // handle updated entries }
    public void presenceChanged(Presence presence) { // handle presence change }
});

它还提供了一种保护用户隐私的方法,方法是确保只有经过批准的用户才能订阅名单。为此,Smack 实现了基于权限的模型。

有三种方法可以使用 Roster.setSubscriptionMode() 方法处理状态订阅请求:

  • Roster.SubscriptionMode.accept_all – 接受所有订阅请求
  • Roster.SubscriptionMode.reject_all—— 拒绝所有订阅请求
  • Roster.SubscriptionMode.manual – 手动处理状态订阅请求

如果我们选择手动处理订阅请求,则需要注册一个 StanzaListener(在下一节中描述)并使用 Presence.Type.subscription 类型处理数据包。

7. Stanza

除了聊天之外,Smack 还提供了一个灵活的框架来发送Stanza并侦听传入的Stanza。

澄清一下,节是 XMPP 中离散的语义意义单位。它是通过 XML 流从一个实体发送到另一个实体的结构化信息。

我们可以使用 send() 方法通过连接传输Stanza:

代码语言:javascript代码运行次数:0运行复制
Stanza presence = new Presence(Presence.Type.subscribe);
connection.sendStanza(presence);

在上面的示例中,我们发送了一个状态Stanza来订阅名单。

另一方面,为了处理传入的节,库提供了两个构造:

  • StanzaCollector
  • StanzaListener

特别是,StanzaCollector 让我们同步等待新的Stanza

代码语言:javascript代码运行次数:0运行复制
StanzaCollector collector
  = connection.createStanzaCollector(StanzaTypeFilter.MESSAGE);
Stanza stanza = collector.nextResult();

虽然 StanzaListener 是一个接口,用于异步通知我们传入的Stanza

代码语言:javascript代码运行次数:0运行复制
connection.addAsyncStanzaListener(new StanzaListener() {
    public void processStanza(Stanza stanza) 
      throws SmackException.NotConnectedException,InterruptedException, 
        SmackException.NotLoggedInException {
            // handle stanza
        }
}, StanzaTypeFilter.MESSAGE);

7.1. 过滤器

此外,该库提供了一组内置的过滤器来处理传入的Stanza

我们可以使用 StanzaTypeFilter 按类型过滤Stanza,也可以使用 StanzaIdFilter 按 ID 过滤Stanza

代码语言:javascript代码运行次数:0运行复制
StanzaFilter messageFilter = StanzaTypeFilter.MESSAGE;
StanzaFilter idFilter = new StanzaIdFilter("123456");

或者,通过特定地址辨别:

代码语言:javascript代码运行次数:0运行复制
StanzaFilter fromFilter
  = FromMatchesFilter.create(JidCreate.from("baeldung@jabb3r"));
StanzaFilter toFilter
  = ToMatchesFilter.create(JidCreate.from("baeldung2@jabb3r"));

我们可以使用逻辑过滤器运算符(AndFilterOrFilterNotFilter)来创建复杂的过滤器:

代码语言:javascript代码运行次数:0运行复制
StanzaFilter filter
  = new AndFilter(StanzaTypeFilter.Message, FromMatchesFilter.create("baeldung@jabb3r"));

8. 结论

在本文中,我们介绍了Smack提供的现成最有用的类。

我们学习了如何配置库以发送和接收 XMPP 的Stanza

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2021-08-17,如有侵权请联系 cloudcommunity@tencent 删除客户端连接javasmackxmpp

本文标签: XMPP Smack 客户端指南