文章参考自:
https://www.cnblogs.com/tudou008/p/5484911.html
https://www.cnblogs.com/fvsfvs123/p/4178117.html
https://blog.csdn.net/eeeggghit/article/details/83507563
https://blog.csdn.net/huang1196/article/details/38401197
version: release 1.3.2
Part 1: 进程结构和启动流程
作为独立application启动后,进程结构图如下:
未命名进程标识:
- <0.97.0>: ranch_app
- <0.103.0>: ranch_listerner_sup
- <0.104.0>: ranch_conn_sup
- <0.105.0>: ranch_acceptors_sup
作为独立application启动流程:
然后在自己的application中调用
需要了解的api:
- supervisor:start_link() 启动一个监督进程
- supervisor:start_child() 在指定监督进程下,启动一个子进程
- gen_tcp:controlling_process() 将指定socket的控制权转移给指定的进程
Part2: 代码细节
-
gen_tcp:accept 得到socket的active 属性是 {active, false}, 这种情况下要接收socket的消息, 方法只有手动调用 gen_tcp:recv 阻塞等待消息到来. (tcp_echo例子), 要么 inet:setopt(Socket, [{active, once}]. 这样每当有消息到来,就会通知进程(仅一次, 处理完消息后,下次仍需手动设置为 [{active,once}]).
-
tcp_reverse例子中,ProtocolProc是gen_server行为, gen_server:start_link需要把Mod:init调用完毕后,才算启动完成,返回{ok, Pid}, 那么在Mod:init中调用了 ranch:accept_ack, 会处于一直等待shoot消息,而shoot消息需要ProtocolProc进程启动者,ranch_conn_sup发送,但ranch_conn_sup又无法获取到ProtocolProcPid,所以不能发送消息,两个进程处于互相等待状态 . 所以官方给出解决方法是 Mod:start_link函数体内,使用 proc_lib:spawn_link 启动ProcotolProc,马上返回Pid到ranch_conn_sup, 然后调用Mod:init函数,等待shoot消息到来,之后再调用 gen_server:enter_loop , 状态进入gen_server:loop函数中,表现与正常的gen_server一样.
-
tcp_reverse例子中, 消息处理完毕后,返回结果第三个参数传入超时时间,这样5秒后进程无消息到达则会收到 timeout 消息,返回 {stop, normal, State} 进入关闭进程处理.
-
ranch_server进程本质上是一个管理各个连接实例Ref的角色,拥有一张Ets表,存储的信息有
①. {conns_sup, Ref}: 实例的ranch_conns_sup进程Pid
②. {addr, Ref}: 实例的inet:sockname(ListenSocket)信息
③. {max_conns, Ref}: 实例的最大连接数
④. {opts, Ref}: 实例的传输层参数(TransOpt}.
实例启动和停止都会涉及ranch_server信息修改, 有了ranch_server这些基础工作,ranch才能实现多实例管理. -
应用到自己的项目,注意要修改Opts参数,主要是 {port,max_connections} 这两个参数.
ranch_tcp的opt的所有可选参数在 ranch_tcp文件头部可见,ranch_ssl的opt则在ranch_ssl文件头部可见.