gpt4 book ai didi

sockets - 由于端口命令没有返回,进程在 gen_tcp send/2 中被阻止

转载 作者:行者123 更新时间:2023-12-03 11:55:28 28 4
gpt4 key购买 nike

编辑于 2015-11-25 02:10

我的 ejabberd 版本是 14.12 和 erlang R17B,所以这段代码似乎没用,因为 R17B 中的 erlang:system_info(otp_release) 重新运行“17”

ejabberd_listener.erl

                SockOpts2 =
try erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true} | SockOpts];
false -> SockOpts
catch
_:_ -> []
end,

我在listen选项中手动添加了{send_timeout_close,true},我的问题似乎得到了解决,因为socket在发送超时的同时关闭,尝试在队列中发送后续消息会收到{error,enotconn}响应。
当 {gen_event, 'closed'} msg 来临时,c2s 进程正常终止。

编辑于 2015-11-24 03:40

也许我找到了重现此问题的方法:
1.与xmpp客户端建立正常的c2s连接
2.用一些工具切断客户端的网络,例如。笨拙(从服务器丢弃所有 tcp 数据包)
3.不断向c2s进程发送大包

一开始, gen_tcp:send 在 sendbuffer 填满之前返回 ok
然后, gen_tcp:send 重新运行 {error,timeout} 因为 sendbuffer 已满
进程调用 ejabberd_socket:close(Socket) 关闭连接
   send_text(StateData, Text) when StateData#state.mgmt_state == active ->
catch ?INFO_MSG("Send XML on stream = ~ts", [Text]),
case catch (StateData#state.sockmod):send(StateData#state.socket, Text) of
{'EXIT', _} ->
(StateData#state.sockmod):close(StateData#state.socket),
error;
_ ->
ok

结尾;

但是 ejabberd_socket:close/1 似乎是一个异步调用,所以 c2s 进程会处理 message_queue 中的下一条消息,继续调用 gen_tcp:send/2,等待一个 send_timeout。

但是此时ejabberd_receiver调用了gen_tcp:close(Socket),socket关闭了,所以之前的gen_tcp:send/2永远不会返回。我已经用这种方法尝试了几次,它发生了 100%。

简而言之,如果我将数据包发送到无法接收数据包的客户端套接字并且发送缓冲区已满,我会在发送超时后收到{错误,超时}。但是,如果另一个异步进程在我等待 gen_tcp:send/2 的发送超时时关闭了套接字,我将永远不会得到响应。


所以,我用 erl 做了这个,而 gen_tcp:send/2 没有响应(在第 3 步切断网络,继续发送数据包,异步关闭)。
我想知道这是一个问题还是因为我自己的原因?
enter image description here



下面是原帖

通常在 ejabberd 中,我将消息路由到客户端进程,通过此函数发送到 tcp 套接字。它在大多数时候都运行良好。
模块 ejabberd_c2s.erl
   send_text(StateData, Text) when StateData#state.mgmt_state == active ->
catch ?INFO_MSG("Send XML on stream = ~ts", [Text]),
case catch (StateData#state.sockmod):send(StateData#state.socket, Text) of
{'EXIT', _} ->
(StateData#state.sockmod):close(StateData#state.socket),
error;
_ ->
ok
end;

但在某些情况下,c2s pid 像这样在 gen_tcp:send 上阻塞
erlang:process_info(pid(0,8353,11)).
[{current_function,{prim_inet,send,3}},
{initial_call,{proc_lib,init_p,5}},
{status,waiting},
{message_queue_len,96},
{messages ...}
...

大多数情况发生在用户的网络状态不太好时,接收进程应该向 c2s pid 发送 2 条消息,c2s 将终止 session 或等待恢复

{'$gen_event',关闭}

{'DOWN',#Ref<0.0.1201.250595>,进程,<0.19617.245>,正常}

我在c2s进程中打印了消息队列,2个消息在队列中,等待处理。很遗憾,
队列不再移动,因为进程在处理这些消息之前已阻塞,如上所述,在尝试执行 gen_tcp:send/2 时堆叠在 prim_inet:send/3。
几天后队列变得非常大,当进程要求更多内存时,ejabberd 崩溃。
prim_inet:send/3 source :
send(S, Data, OptList) when is_port(S), is_list(OptList) ->
?DBG_FORMAT("prim_inet:send(~p, ~p)~n", [S,Data]),
try erlang:port_command(S, Data, OptList) of
false -> % Port busy and nosuspend option passed
?DBG_FORMAT("prim_inet:send() -> {error,busy}~n", []),
{error,busy};
true ->
receive
{inet_reply,S,Status} ->
?DBG_FORMAT("prim_inet:send() -> ~p~n", [Status]),
Status
end
catch
error:_Error ->
?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []),
{error,einval}
end.

似乎端口驱动程序在 erlang:port_command(S, Data, OptList) 之后没有回复 {inet_reply,S,Status} 。
gen_tcp:send 函数会阻塞无穷大,谁能解释一下?

最佳答案

这取决于您使用的 Erlang 版本。在旧的 ejabberd 版本上不使用 gen_tcp send 超时选项,因为当时它在 Erlang 中不可用。此外,您必须使用最新版本的 Erlang,因为 Erlang 本身已经修复了一些关于该选项的错误。

关于sockets - 由于端口命令没有返回,进程在 gen_tcp send/2 中被阻止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33338905/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com