这篇文章是我之前在RYTong内部分享的一篇文章。上一篇文章说到Ejabberd在启动的时候会监听配置的端口,但没有详细解释监听的流程。这篇我们就来看看Ejabberd监听端口的实现逻辑,了解下一个XMPP实体如何连接到Ejabberd,Ejabberd又是如何将该实体发送的报文转发给目标实体的。
端口监听与连接建立
在介绍启动流程时已经提到Ejabberd会使用ejabberd_listener:start/3方法创建一个Worker进程,这个进程负责接收TCP连接。start/3方法最终会使用gen_tcp:listen/2函数监听指定端口,并调用本地accept/3方法来接收TCP连接。
accept(ListenSocket, Module, Opts) ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
case {
inet:sockname(Socket), inet:peername(Socket)} of
{
{ok, Addr}, {ok, PAddr}} ->
?INFO_MSG("(~w) Accepted connection ~w -> ~w",
[Socket, PAddr, Addr]);
_ ->
ok
end,
CallMod = case is_frontend(Module) of
true -> ejabberd_frontend_socket;
false -> ejabberd_socket
end,
CallMod:start(strip_frontend(Module), gen_tcp, Socket, Opts),
accept(ListenSocket, Module, Opts);
{error, Reason} ->
?ERROR_MSG("(~w) Failed TCP accept: ~w",
[ListenSocket, Reason]),
accept(ListenSocket, Module, Opts)
end.
如上,accept/3方法会调用gen_tcp:accept/1方法来接收连接,并使用ejabberd_socket:start/4函数来处理每个连接。ejabberd_socket:start/4函数会为每个连接启动两个进程:一为ejabberd_receiver,另一个为使用listen配置项中该端口配置的Module(ejabberd_c2s或ejabberd_s2s)的start/2方法启动的进程。
{
ReceiverMod, Receiver, RecRef} =
case catch SockMod:custom_receiver(Socket) of
{receiver, RecMod,