http://my.oschina.net/astute/blog/119250?p=1

在看ranch user guide的过程中,发现实现protocol handler需要使用特殊的gen_server形式,也就是enter_loop函数调用,事例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-module(echo_protocol).
-behaviour(ranch_protocol).
  
-export([start_link/4]).
-export([init/4]).
  
start_link(ListenerPid, Socket, Transport, Opts) ->
    Pid = spawn_link(?MODULE, init, [ListenerPid, Socket, Transport, Opts]),
    {ok, Pid}.
  
init(ListenerPid, Socket, Transport, _Opts = []) ->
    ok = ranch:accept_ack(ListenerPid),
    loop(Socket, Transport).
  
loop(Socket, Transport) ->
    case Transport:recv(Socket, 0, 5000) of
        {ok, Data} ->
            Transport:send(Socket, Data),
            loop(Socket, Transport);
        _ ->
            ok = Transport:close(Socket)
    end.

实现ranch的protocol handler只需要实现start_link函数即可,函数中需要启动一个新的进程,新的进程需要调用accept_ack函数来绑定socket的owner进程。

如果回调要实现gen_server行为模式的话,Listener进程调用模块的start_link方法,内部同步的启动gen_server进程,并且等待gen_server进程调用init函数返回,如果这个时候在init的方法中调用accept_ack方法,就会造成循环调用,造成死锁。

ranch提供的方法如下,使用gen_server的enter_loop方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-module(my_protocol).
-behaviour(gen_server).
-behaviour(ranch_protocol).
  
-export([start_link/4]).
-export([init/1]).
%% Exports of other gen_server callbacks here.
  
start_link(ListenerPid, Socket, Transport, Opts) ->
    proc_lib:start_link(?MODULE, [[ListenerPid, Socket, Transport, Opts]]).
 
init(ListenerPid, Socket, Transport, _Opts = []) ->
    ok = proc_lib:init_ack({ok, self()}),
    %% Perform any required state initialization here.
    ok = ranch:accept_ack(ListenerPid),
    ok = Transport:setopts(Socket, [{active, once}]),
    gen_server:enter_loop(?MODULE, [], {state, Socket, Transport}).
 
%% Other gen_server callbacks here.

通常情况下启动gen_server,需要调用gen_server:start_link(),参数中设置回调模块,这样的话像上面的分析,是会有死锁的问题的。

规避这个问题就是使用enter_loop方法。这个方法可以让已经存在的独立进程成为gen_server进程,在进入普通的gen_server循环之前执行设定的逻辑。

Listener进程调用proc_lib:start_link方法,创建新进程A,A执行init方法,调用proc_lib:init_ack()方法,告诉listener进程A进程已经启动,此时Listener进程就可以返回了。然后A进程再执行accept_ack()方法,最后调用enter_loop方法,让自己进入gen_server的执行循环。

gen_server的enter_loop分析的更多相关文章

  1. Gen_server行为分析与实践

    1.简介 Gen_server实现了通用服务器client_server原理,几个不同的客户端去分享服务端管理的资源(如图),gen_server提供标准的接口函数和包含追踪功能以及错误报告来实现通用 ...

  2. gen_server port 调用receive_match 问题

    问题由来 前些天对系统做了一个优化,将原来从queue 轮询刷出数据后每条消息一个 spawn 进程单独处理,修改为批量刷出.一条一条刷轮询刷 queue 存在问题:刷queue 进程太多时,占用CP ...

  3. Erlang generic standard behaviours -- gen_server module

    在分析完gen module (http://www.cnblogs.com/--00/p/4271386.html)之后,就可以开始进入gen_server 的主体module 了.gen_serv ...

  4. Supervisor行为分析和实践

    1.简介     Erlang要编写高容错性.稳定性的系统,supervisor就是用来解决这一问题的核心思想.通过建立一颗监控树,来组织进程之间的关系,通过确定重启策略.子进程说明书等参数信息来确定 ...

  5. Erlang模块gen_server翻译

    gen_server 概要: 通用服务器行为描述: 行为模块实现服务器的客户端-服务器关系.一个通用的服务器进程使用这个模块将实现一组标准的接口功能,包括跟踪和错误报告功能.它也符合OTP进程监控树. ...

  6. Erlang gen_server进程花样作死

    本文主要记录各种情况下gen_server进程退出的表现. 研究动机起源于Elixir/Phoenix框架中遇到的一个进程异常退出问题.因为网络异常,客户端超过一段时间未发来消息,channel进程( ...

  7. gen_server terminate与trap_exit

    不论是新手还是熟手,写gen_server时常会遇到terminate/2,有时执行,有时却不执行的困惑. 比如stackoverflow中的Handling the cleanup of the g ...

  8. Erlang的gen_server的terminate()/2未执行

    官方资料参考: Module:terminate(Reason, State) Types: Reason = normal | shutdown | {shutdown,term()} | term ...

  9. [Erlang21]Erlang性能分析工具eprof fporf的应用

    前段时间项目改代码突然cpu波动很大,排查了好久都没有找到原因,只能求助于性能测试工具 :   <<Erlang程序设计>>----Joe Armstorng[哈哈,登月第一人 ...

随机推荐

  1. ORA-00957: 反复的列名

    1.错误描写叙述 ORA-00957: 反复的列名 2.错误原因 SQL> create table info( 2 stu_id varchar2(7) not null, 3 stu_nam ...

  2. 内网使用 IPV6 之 TunnelBroker隧道(6in4)篇

    内网使用 IPV6 之 TunnelBroker隧道(6in4)篇 据非专业网民推测 tunnelbroker isatap 和 6to4  貌似都需要公网,但有网民测试这位大作的方法可行.特别之处是 ...

  3. 每日技术总结:fly.js,个位数前补零等

    01.FLY.JS 文档:https://wendux.github.io/dist/#/doc/flyio/readme 02.微信小程序组件——input属性之cursor-spacing 属性 ...

  4. 【习题 6-5 UVA-1600】Patrol Robot

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 设dis[x][y][z]表示到(x,y)连续走了z个墙的最短路 bfs一下就ok [代码] /* 1.Shoud it use l ...

  5. Something-Summary

    1.Combinatorial Mathematics 1.1 Bell Number: \(B_n\)表示元素个数为n的集合划分成若干个不相交集合的方案数. \(B_{n + 1} = \sum_{ ...

  6. 【Codeforces Round #299 (Div. 2) D】Tavas and Malekas

    [链接] 我是链接,点我呀:) [题意] 给你n个位置,然后让你从某些位置开始的|p|个位置,填上p这个字符串. 问你填的时候是否会发生冲突->输出0 否则输出最终n个位置组成的可能的字符串的总 ...

  7. 让自己的软件实现拖拽打开文件(覆盖WM_DROPFILES,使用DragQueryFile,DragFinish API函数)

    作者: 帅宏军 //声明 protected    procedure WMDROPFILES(var Msg : TMessage); message WM_DROPFILES; --------- ...

  8. php实现运气模型(命运随机,克服困难)

    php实现运气模型(命运随机,克服困难) 一.总结 1.应该用表格来布局的,这种多列的用表格布局比div和span布局方便很多 2.span标签设置宽度:变成行内快元素:display:inline- ...

  9. 【BZOJ 4199】 [Noi2015]品酒大会

    [链接]h在这里写链接 [题意]     给你一个长度为n的字符串s;     标志了每一杯酒;     以及n个数字,表示每一杯酒的美味度ai.     两杯酒(i,j)称为r相似     当且仅当 ...

  10. HDU 1800 Flying to the Mars Trie或者hash

    http://acm.hdu.edu.cn/showproblem.php?pid=1800 题目大意: 又是废话连篇 给你一些由数字组成的字符串,判断去掉前导0后那个字符串出现频率最高. 一开始敲h ...