Erlang:使用gen_tcp:controlling_process避免竞争条件 [英] Erlang: Avoiding race condition with gen_tcp:controlling_process

查看:607
本文介绍了Erlang:使用gen_tcp:controlling_process避免竞争条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  {ok,LS} = gen_tcp:listen(Port, [{active,true},{reuseaddr,true},{mode,list}]),
{ok,Socket} = gen_tcp:accept(LS),
Pid = spawn_link(M, [Socket]),
gen_tcp:controls_process(Socket,Pid)

使用选项{ active,true}可能会在control_process被调用之前引起新数据包到达套接字进程的竞争条件,这将导致{tcp,Socket,Data}消息到达父进程而不是子进程。 p>

如何避免这种情况?

解决方案

你是对的在这种情况下,您肯定需要在侦听套接字选项之间传递 {active,false} 。考虑这段代码:

  -define(TCP_OPTIONS,[binary,{active,false},...])。 

...

start(Port) - >
{ok,Socket} = gen_tcp:listen(Port,?TCP_OPTIONS),
accept(Socket)。

accept(ListenSocket) - >
case gen_tcp:accept(ListenSocket)
{ok,Socket} - >
Pid = spawn(fun() - >
io:format(Connection accepted〜n,[]),
enter_loop(Socket)
end),
gen_tcp:controlling_process(Socket,Pid),
Pid! ack,
accept(ListenSocket);
错误 - >
退出(错误)
结束。

enter_loop(Sock) - >
%%确保确认所有者权限传输完成
接收ack - > ok结束,
loop(Sock)。

loop(Sock) - >
%%设置soscket选项直接接收消息
inet:setopts(Sock,[{active,once}]),
接收
{tcp,Socket,Data} - >
io:format(Got packet:〜p〜n,[Data]),
...,
loop(Socket);
{tcp_closed,Socket} - >
io:format(Socket〜p closed〜n,[Socket]);
{tcp_error,套接字,原因} - >
io:format(套接字上的错误〜p原因:〜p〜n,[Socket,Reason])
结束。

因此,直到 controlling_process 成功。已知的问题已经在互联网上讨论了很多。
如果您希望使用即时解决方案,您一定需要查看牧场项目。


I am implementing simple tcp server with the following sequence:

{ok, LS} = gen_tcp:listen(Port,[{active, true}, {reuseaddr, true}, {mode, list}]),
{ok, Socket} =  gen_tcp:accept(LS),
Pid = spawn_link(M, F, [Socket]),           
gen_tcp:controlling_process(Socket, Pid) 

Using the option {active, true} might cause a race condition where a new packet arrives on the socket process before the "controlling_process" get called , which would result in {tcp,Socket,Data} message arriving to the father proccess instead of the child.

How this could be avoided ?

解决方案

You are right. In such cases you surely need {active, false} passed among listening socket options. Consider this snippet of code:

-define(TCP_OPTIONS, [binary, {active, false}, ...]).

...

start(Port) ->
    {ok, Socket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
    accept(Socket).

accept(ListenSocket) ->
    case gen_tcp:accept(ListenSocket) of
        {ok, Socket} ->
            Pid = spawn(fun() ->
                io:format("Connection accepted ~n", []),
                enter_loop(Socket)
            end),
            gen_tcp:controlling_process(Socket, Pid),
            Pid ! ack,
            accept(ListenSocket);
        Error ->
            exit(Error)
    end.

enter_loop(Sock) ->
    %% make sure to acknowledge owner rights transmission finished
    receive ack -> ok end,
    loop(Sock).

loop(Sock) ->
    %% set soscket options to receive messages directly into itself
    inet:setopts(Sock, [{active, once}]),
    receive
        {tcp, Socket, Data} ->
            io:format("Got packet: ~p~n", [Data]),
            ...,
            loop(Socket);
        {tcp_closed, Socket} ->
            io:format("Socket ~p closed~n", [Socket]);
        {tcp_error, Socket, Reason} ->
            io:format("Error on socket ~p reason: ~p~n", [Socket, Reason])
    end.

Thus you will not lost anything until controlling_process succeeds. It is known problem been discussed a lot over internets. If you wish to use ready to go solution you surely need to take a look at Ranch project.

这篇关于Erlang:使用gen_tcp:controlling_process避免竞争条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆