Erlang接受消息循环

Erlang的Socket编程中,Socket的归属权至关重要,只有创建进程才能处理Socket消息,但可通过gen_tcp:controlling_process()转移控制权。在游戏开发中,常采用阻塞模式{active, false}进行消息处理。尽管如此,在特定情况下,非归属进程仍能接收Socket消息。" 107478466,8765397,Kotlin面试必备:核心问题与解答,"['Kotlin', '面试问题', 'Android开发', '编程语言']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

重点:Socket有归属权,只有创建的进程才有资格处理,除非使用gen_tcp:controlling_process(Socket,Pid).,把该Socket的控制权交给Pid进程。

游戏中主要使用阻塞模式{active, fasle}


1、主动型消息接收(非阻塞):{active,true}
如果客户端发送的数据过快服务器可以处理的速度,那么系统就会被消息淹没,不会阻塞客户端,也叫异步服务器。
start()- >
{ok,Listen}=gen_tcp:listen(Port,[...,{active,true}...]),
{ok,Socket}=gen_tcp:accept(Listen),
loop(Socket).

loop(Socket)->
     receive
          {tcp,Socket,Data}->
               ... do something with the data ...
          {tcp_closed,Socket}->
               ...
     end.
也叫异步服务器,不会阻塞客户端

2、被动型消息接收(阻塞):{active,false}
不会因为一个过于活跃的客户机通过发送大量数据的攻击而崩溃。调用gen_tcp:recv时会阻塞客户端。需要注意的是,操作系统还会做一些缓存允许客户端继续发送少量的数据,然后才会将其阻塞,此时Erlang还没有调用到recv函数(?,我猜是这些少量数据压在邮箱中)。
start()- >
{ok,Listen}=gen_tcp:listen(port,[...,{active,false}...]),
{ok,Socket}=gen_tcp:accept(listen),
loop(Socket).

loop(Socket)->
     case gen_tcp:recv(Socket,N) of
          {ok,B}->
               ...do something with the data...
               loop(Socket);
          {error,closed}
               ...
     end.

3、混合型模式(半阻塞),{active,once}
既不是阻塞也不是非阻塞。
{active,once}选项打开套接字。这种模式,套接字是主动但是仅仅针对一个消息,在控制进程发过一个消息后,必须显示地调用函数inet:setopts来把它重新激活以便接受下一个消息在此之前,系统会处于阻塞状态。
start()- >
{ok,Listen}=gen_tcp:listen(Port,[...,{active,once}...]),
{ok,Socket}=gen_tcp:accept(Listen),
loop(Socket).

loop(Socket)->
     receive
          {tcp,Socket,Data}->
               ... do something with the data...
             %%when you're ready enable the next message
               inet:setopts(Sock,[{active,once}]),  %%使用inet:setopts来激活,但是消耗资源
               loop(Socket);
          {tcp_closed,Socket}->
               ...
     end.

4、有关归属权问题

第一种模式中,我改改,黑体是改的部分。这是错误的,Socket的归属权在start()的进程中,接受不了该Socket发送的消息。 第三种模式也是如此。(第二种模式比较特殊,继续看下面)
start()- >
{ok,Listen}=gen_tcp:listen(Port,[...,{active,true}...]),
{ok,Socket}=gen_tcp:accept(Listen),
spawn(fun() -> loop(Socket) end).%%创建接受数据进程

loop(Socket)->
     receive
          {tcp,Socket,Data}->
               ... do something with the data ...
          {tcp_closed,Socket}->
               ...
     end.


改成:

start()- >
{ok,Listen}=gen_tcp:listen(Port,[...,{active,true}...]),
{ok,Socket}=gen_tcp:accept(Listen),
register(Pid,spawn(fun() -> loop(Socket) end)). %%创建接受数据进程,并注册成Pid
gen_tcp:controlling_process(Socket,Pid).

loop(Socket)->
     receive
          {tcp,Socket,Data}->
               ... do something with the data ...
          {tcp_closed,Socket}->
               ...
     end.

特别的地方,有关第二种模式的Socket归属权的话,这个还是能获取到消息的·,是没问题的。

start()- >
{ok,Listen}=gen_tcp:listen(port,[...,{active,false}...]),
{ok,Socket}=gen_tcp:accept(listen),
spawn(fun() -> loop(Socket) end)

loop(Socket)->
     case gen_tcp:recv(Socket,N) of
          {ok,B}->
               ...do something with the data...
               loop(Socket);
          {error,closed}
               ...
     end.

@@本文参考Erlang程序设计@@


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值