BLOG
Enjoy when you can, and endure when you must.
DEC 22, 2014/编程相关
XMPP:Play with It

前面谈了最基本的理论,现在就从应用的角度入手来实际感受下 XMPP。

从服务器来看,开源的 XMPP 服务器软件有很多,这里以 Openfire 为例,具体的搭建过程就不细说了,其管理后台如下:

我们可以切换到“用户/组”标签下新建几个用户以方便之后的实验。如下图所示有两个测试账户 user1 和 user2:

现在让我们切换到用户角色。首先使用一个配套工具 Spark 来尝试一下。在登录界面解决输入之前的账户和服务器信息即可:

  

不过这里建议在设置中打开调试模式点击登录以后即可看到好友列表和调试窗口。特别是调试窗口可以让一切与服务器的交互都一目了然,很方便学习和跟踪。

接下来再进一步回归原始,用 Python 来连接 XMPP。开始之前,不得不提一个名词:事件驱动编程。为需要处理的事件编写相应的事件处理程序,代码在事件发生时执行。在 XMPP 中就会用到这种编程模式,服务器向客户端的通信是随机发生的,我们要做的是接受来自服务端的事件并使用正确的代码来处理。关于事件驱动编程,Python 中有一个 Twisted 库很值得深入研究一下。

那回到我们的主题,这里将用到一个不错的第三方库 SleekXMPP(如果没有安装,pip 一下即可到手)。目标很简单,登录到 Openfire,并接收和发送消息。与使用 Spark 这样的软件类似,要想登录到 XMPP 服务器,需要的是一个有效的用户名、密码及服务器地址,如下所示:

>>> from sleekxmpp import ClientXMPP
>>> xmpp = ClientXMPP(jid='user2@localhost.localdomain', password='111111')
DEBUG    Loaded Plugin: RFC 6120: Stream Feature: STARTTLS
DEBUG    Loaded Plugin: RFC 6120: Stream Feature: Resource Binding
DEBUG    Loaded Plugin: RFC 3920: Stream Feature: Start Session
DEBUG    Loaded Plugin: RFC 6121: Stream Feature: Roster Versioning
DEBUG    Loaded Plugin: RFC 6121: Stream Feature: Subscription Pre-Approval
DEBUG    Loaded Plugin: RFC 6120: Stream Feature: SASL

实例化 ClientXMPP 类并传入初始化参数,其中 jid 中的 user2 是要登录的用户名,而 localhost.localdomain 则是 Openfire 服务器的域名。接着调用 connect() 方法即可连接到服务器,其第一个参数为 address,接收一个元组,用以显示提供服务器地址和端口号(在这里必须提供该参数,因为在该演示中我并不在 Openfire 本机上做登录,而指定的域却是 localhost.localdomain)。

>>> xmpp.connect(address=('192.168.242.137', '5222'))

最后还差一步,需要进一步调用 process() 方法来启动事件循环(event loop)。在前面已经提到,我们现在面对的是事件驱动编程模式,事件循环会等待并发现到来的事件并调用预先设定的方法来处理该事件。我们的目标是登录并能接受到消息,因此需要至少监听两个事件:session_start 和 message 。session_start 在与服务器建立连接成功后触发,我们可以利用该事件来通知服务器和其他人“我来了!”。而 message 事件则是在接收到消息推送后触发。

>>> def handle_incoming_message(message):
	print 'Received message from {0}: {1}'.format(message['from'], message['body'])

>>> def handle_xmpp_connected(event):
	xmpp.send_presence()

>>> xmpp.add_event_handler('session_start', handle_xmpp_connected)
>>> xmpp.add_event_handler('message', handle_incoming_message)
>>> xmpp.process()

如果一切顺利的话,这时应已成功连接到 Openfire 并开始了事件监听。可以查看 authenticated 属性来验证成功与否:

>>> xmpp.authenticated
True

在 Openfire 管理控制台的“会话”标签下也应能看到所登录的账户:

我们可以尝试从 Spark 向 user2 发送一条消息“Hi, My Friend!”。

DEBUG    RECV: <message to="user2@localhost.localdomain" from="user1@localhost.localdomain/Spark 2.6.3" id="3T9L3-59" type="chat"><body>Hi, My Friend!</body><thread>ErB6Wg</thread><x xmlns="jabber:x:event"><offline /><composing /></x></message>
DEBUG    Event triggered: message
Received message from user1@localhost.localdomain/Spark 2.6.3: Hi, My Friend!

这里我开启了 log,因此可以看到几条 DEBUG 日志。

要发送消息呢?很简单,调用 send_message() 方法即可。

xmpp.send_message(mto='user1@localhost.localdomain', mbody='Nict to meet you!', mtype='chat')
DEBUG    SEND: <message to="user1@localhost.localdomain" type="chat" xml:lang="en"><body>Nict to meet you!</body></message>

是不是很有趣呢?接下来的深入研究就靠大家自己了。

COMMENTS
LEAVE COMMNT