Перейти к основному содержимому

Руководство по XMPP-клиенту Smack

· 6 мин. чтения

1. Введение

XMPP — это многофункциональный и сложный протокол обмена мгновенными сообщениями.

Вместо того, чтобы писать собственный клиент с нуля, в этом руководстве мы рассмотрим Smack, модульный и переносимый XMPP-клиент с открытым исходным кодом, написанный на Java , который сделал за нас большую часть тяжелой работы.

2. Зависимости

Smack организован в виде нескольких модулей для обеспечения большей гибкости , поэтому мы можем легко включать нужные нам функции.

Некоторые из них включают:

  • Модуль XMPP через TCP
  • Модуль для поддержки многих расширений, определенных Фондом стандартов XMPP.
  • Поддержка устаревших расширений
  • Модуль для отладки

Мы можем найти все поддерживаемые модули в документации XMPP .

Однако в этом руководстве мы будем использовать только модули tcp , im , extensions и java7 :

<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.net , бесплатном сервисе Jabber/XMPP для всех.

После этого мы можем настроить Smack, используя класс XMPPTCPConnectionConfiguration , который предоставляет сборщик для настройки параметров соединения:

XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setUsernameAndPassword("foreach","foreach")
.setXmppDomain("jabb3r.org")
.setHost("jabb3r.org")
.build();

Построитель позволяет нам установить основную информацию, необходимую для выполнения соединения . При необходимости мы также можем установить другие параметры, такие как порт, протоколы SSL и тайм-ауты.

4. Подключение

Создание соединения просто достигается с помощью класса XMPPTCPConnection :

AbstractXMPPConnection connection = new XMPPTCPConnection(config);
connection.connect(); //Establishes a connection to the server
connection.login(); //Logs in

Класс содержит конструктор, принимающий созданную ранее конфигурацию. Он также предоставляет методы для подключения к серверу и входа в систему.

Как только соединение установлено, мы можем использовать функции Smack , такие как чат , которые мы опишем в следующем разделе.

В случае, если соединение было внезапно прервано, по умолчанию Smack попытается восстановить соединение.

ReconnectionManager попытается немедленно переподключиться к серверу и увеличить задержку между попытками, поскольку последовательные переподключения продолжают давать сбой .

5. Чат

Одной из главных особенностей библиотеки является поддержка чата.

Использование класса Chat позволяет создать новый поток сообщений между двумя пользователями:

ChatManager chatManager = ChatManager.getInstanceFor(connection);
EntityBareJid jid = JidCreate.entityBareFrom("foreach2@jabb3r.org");
Chat chat = chatManager.chatWith(jid);

Обратите внимание, что для создания чата мы использовали ChatManager и, очевидно, указали, с кем общаться. Мы достигли последнего, используя объект EntityBareJid , который заключает в себе XMPP-адрес — он же JID — состоящий из локальной части ( foreach2 ) и доменной части ( jabb3r.org ). **** ``

После этого мы можем отправить сообщение с помощью метода send() :

chat.send("Hello!");

И получать сообщения, установив прослушиватель:

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 обеспечивает поддержку групповых чатов за счет использования комнат .

Есть два типа комнат, мгновенные комнаты и зарезервированные комнаты.

Мгновенные комнаты доступны для немедленного доступа и автоматически создаются на основе некоторой конфигурации по умолчанию. С другой стороны, зарезервированные комнаты настраиваются владельцем вручную, прежде чем кто-либо сможет войти.

Давайте посмотрим, как создать мгновенную комнату с помощью MultiUserChatManager :

MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
MultiUserChat muc = manager.getMultiUserChat(jid);
Resourcepart room = Resourcepart.from("foreach_room");
muc.create(room).makeInstant();

Аналогичным образом мы можем создать зарезервированную комнату:

Set<Jid> owners = JidUtil.jidSetFrom(
new String[] { "foreach@jabb3r.org", "foreach2@jabb3r.org" });

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

6. Состав

Еще одна функция, которую предоставляет Smack, — это возможность отслеживать присутствие других пользователей.

С помощью Roster.getInstanceFor() мы можем получить экземпляр Roster :

Roster roster = Roster.getInstanceFor(connection);

Roster — это список контактов, который представляет пользователей как объекты RosterEntry и позволяет нам организовывать пользователей в группы.

Мы можем распечатать все записи в реестре , используя метод getEntries() :

Collection<RosterEntry> entries = roster.getEntries();
for (RosterEntry entry : entries) {
System.out.println(entry);
}

Более того, он позволяет нам прослушивать изменения в его записях и данных о присутствии с помощью RosterListener:

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.subscribe .

7. Станца

В дополнение к чату Smack предоставляет гибкую структуру для отправки строфы и прослушивания входящей.

Чтобы уточнить, строфа — это дискретная семантическая единица значения в XMPP. Это структурированная информация, которая отправляется от одного объекта к другому через поток XML.

Мы можем передать Stanza через Connection , используя метод send() :

Stanza presence = new Presence(Presence.Type.subscribe);
connection.sendStanza(presence);

В приведенном выше примере мы отправили строфу присутствия , чтобы подписаться на список.

С другой стороны, для обработки входящих строф библиотека предоставляет две конструкции:

  • СтанцаКоллекционер
  • StanzaListener

В частности, StanzaCollector позволяет синхронно ожидать новых строф :

StanzaCollector collector
= connection.createStanzaCollector(StanzaTypeFilter.MESSAGE);
Stanza stanza = collector.nextResult();

В то время как StanzaListener — это интерфейс для асинхронного уведомления нас о входящих строфах :

connection.addAsyncStanzaListener(new StanzaListener() {
public void processStanza(Stanza stanza)
throws SmackException.NotConnectedException,InterruptedException,
SmackException.NotLoggedInException {
// handle stanza
}
}, StanzaTypeFilter.MESSAGE);

7.1. Фильтры

Более того, библиотека предоставляет встроенный набор фильтров для обработки входящих строф.

Мы можем фильтровать строфы по типу с помощью StanzaTypeFilter или по идентификатору с помощью StanzaIdFilter:

StanzaFilter messageFilter = StanzaTypeFilter.MESSAGE;
StanzaFilter idFilter = new StanzaIdFilter("123456");

Или, различая по конкретному адресу:

StanzaFilter fromFilter
= FromMatchesFilter.create(JidCreate.from("foreach@jabb3r.org"));
StanzaFilter toFilter
= ToMatchesFilter.create(JidCreate.from("foreach2@jabb3r.org"));

И мы можем использовать оператор логического фильтра ( AndFilter , OrFilter , NotFilter ) для создания сложных фильтров:

StanzaFilter filter
= new AndFilter(StanzaTypeFilter.Message, FromMatchesFilter.create("foreach@jabb3r.org"));

8. Заключение

В этой статье мы рассмотрели наиболее полезные классы, которые Smack предоставляет в готовом виде.

Мы узнали, как настроить библиотеку для отправки и получения строфы XMPP.

Впоследствии мы научились управлять групповыми чатами с помощью функций ChatManager и Roster .

Как обычно, все примеры кода, показанные в этом руководстве, доступны на GitHub.