erlang之三种socket消息循环

转载:高手http://hi.baidu.com/zai215837829/blog/item/2e8323dc3763c02e5982dd80.html


1、主动消息获取(非阻塞)

第一个例子是以主动模式打开socket,然后接受来自socket的数据:

{ok,Listen} = gen_tcp:listen(Port,[...,{active,true}...]), 

{ok,Socket} = gen_tcp:accept(Listen),  loop(Socket). 

 loop(Socket) -> 

    receive 

     {tcp,Socket,Data} -> ... 输出处理 ... 

     {tcp_closed,Socket} -> ... 

 end.

这个过程无法控制发到服务器循环的消息流,如果客户端产生数据的速度大于服务器消费数据的速度,系统就会收到洪水般地消息-消息缓冲区溢出,系统将会crash并表现怪异。

这种类型的服务器叫做非阻塞服务器,因为它无法阻塞客户端。我们仅在信任客户端的情况下才会使用非阻塞服务器。

 

2   被动消息获取(阻塞)

在这一节,我们写阻塞服务器:服务器以被动模式打开socket,通过 {active,false} 选项。这个服务器不会被危险的客户端洪水袭击。

服务器循环中的代码调用 gen_tcp:recv 来接收数据。客户端在服务器调用 recv 之前会被阻塞。注意OS会对客户端发来的数据做一下缓冲,以允许客户端在服务器调用 recv 之前仍然可以继续发送一小段数据。

{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} -> ... 数据处理 ... loop(Socket); 

    {error,closed} ... 

 end.

 

3   混合消息获取(部分阻塞)

你可能认为把被动模式用到所有服务器上都合适。不幸的是,当我们在被动模式时,我们只能等待来自于一个socket的数据。这对于需要等待多个socket来源数据的服务器则不适用。

幸运的是我们可以用混合方式,既不是阻塞的也不是非阻塞的。我们以一次主动(active once)模式 {active,once} 打开socket。在这个模式中,socket是主动的,但是只能接收一条消息。在控制进程发出一条消息之后,他必须明确的调用 inet:setopts 以便让socket恢复并接收下一条消息。系统在这发生之前会一直阻塞。这是两种世界的最好结合点。如下是代码:

{ok,Listen} = gen_tcp:listen(Port,[...,{active,once}...]),

{ok,Socket} = gen_tcp:accept(Listen), loop(Socket). 

 loop(Socket) ->

   receive 

     {tcp,Socket,Data} -> ... 数据处理 ... %%准备好启用下一条消息时 

                                     inet:setopts(Socket,[{active,once}]),

                                     loop(Socket);

     {tcp_closed,Socket} -> ... 

 end.

使用 {active,once} 选项,用户可以实现高层次的数据流控制(有时叫交通管制),同时又防止了服务器被过多的消息洪水所淹没。



你可能感兴趣的:(erlang之三种socket消息循环)