XMPP 超级总线 eJabberd

DavidAlphaFox · 发布于 2017年12月05日 · 382 次阅读
84794b

Jabber组件协议

前面关于IQ处理的文章中,提到过,可以通过增加IQ处理器来扩展eJabberd。但是这对很多不懂Erlang的同学造成了很大困扰。但是XMPP已经充分考虑到eJabberd作为总线的可能性,因此设计了Jabber组件协议。

简介

传统上有两种完全不同的服务器端组件类型:内部组件( 利用服务器的内部API提供服务)和外部组件(组件在一个协议框架上与服务器联系,因此不依赖任何特定的服务器实现)。
目前使用的组件协议框架使得一个外部组件能够连接到一个服务器(通过适当的配置和验证)并能通过服务器发送和接收XML节。有两种连接方法:“accept”和“connect”。使用“accept”方法时,服务器等待并接受被组件初始化的连接。使用“connect”方法时,由服务器初始化到组件的连接。在实际的使用中,“accept”方法更为常用。

eJabberd中外部组件处理

接入处理

eJabberd是通过ejabberd_service来实现的Jabberd组件协议。在eJabberd启动的时候,会启动一个有别于ejabberd_c2s所监听的XML流端口进行监听,因为jabber组件的XML流处理和eJabberd_c2s的流处理方式完全不同。

组件为了将自己注册到XMPP服务器上,需要和XMPP服务器进行下面交互

组件向服务器发送消息
<stream:stream
    xmlns='jabber:component:accept'
    xmlns:stream='http://etherx.jabber.org/streams'
    to='plays.shakespeare.lit'>

服务器会回应下面的消息
<stream:stream
    xmlns:stream='http://etherx.jabber.org/streams'
    xmlns='jabber:component:accept'
    from='plays.shakespeare.lit'
    id='3BF96D32'>

接着组件要给服务器发送handshake

<handshake>aaee83c26aeeafcbabeabfcbcd50df997e0a2a1e</handshake>

服务器需要给组件回复一个空的handshake来表示确认
<handshake/>

ejabberd_service模块

ejabberd_service的基本流程和ejabebrd_c2s进程是相似的,其中重点是wait_for_handshake的处理,这个函数内会验证handshake中的hash,并将自己注册到路由表的组件相关的表。在注册的过程,会默认注册本地和全集群路由。


wait_for_handshake({xmlstreamelement, El}, StateData) ->
    #xmlel{name = Name, children = Els} = El,
    case {Name, xml:get_cdata(Els)} of
        {<<"handshake">>, Digest} ->
            case sha:sha1_hex(StateData#state.streamid ++
                         StateData#state.password) of
                Digest ->
                    %% 如果handleshake的认证成功了
                    %% 就注册路由信息
                    %% 这里面注册的路由和普通的路由是不同的
                    case register_routes(StateData) of
                        ok ->
                            send_text(StateData, <<"<handshake/>">>),
                            {next_state, stream_established, StateData};
                        {error, Reason} ->
                            ?ERROR_MSG("Error in component handshake: ~p", [Reason]),
                            send_text(StateData, ?CONFLICT_ERR),
                            {stop, normal, StateData}
                    end;
                _ ->
                    send_text(StateData, ?INVALID_HANDSHAKE_ERR),
                    {stop, normal, StateData}
            end;
        _ ->
            {next_state, wait_for_handshake, StateData}
    end;

处理业务

ejabberd_service是外部组件在服务器的代表,如同ejabberd_c2s一样自身并不处理相关业务,只是将数据转发给相应的外部组件。

需要注意的是,由于ejabberd_service在路由中注册本节点内外部服务的时候,是使用mneisa的set,换句话一个外部服务同时只有一个可用,但是注册全集群的时候是使用mnesia的bag,也就是说如果本节点没相应的服务,会向全集群中任何一个有该该外部服务的节点转发消息。

总结

Jabber组件协议,已经将XMPP协议带离一个聊天服务器的范畴了,可以让研发人员不需要改动XMPP服务器就可以轻松扩展。尤其是eJabberd的优良实现,更是将这一特性发挥的非常好。在很多时候,eJabberd完全可以当作一个强大的消息总线来使用,再上面挂接各种服务。

暂无回复。
需要 登录/注册 后方可回复, 如果你还没有账号请点击这里 注册