文章参考自:
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
版本: 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启动流程:
- ranch_app:start()
- ranch_sup:init()
- ranch_server:start_link()
- ranch_server
然后在application中调用
- ranch:start_listener() => ranch_sup 创建 ranch_listener_sup
- ranch_listener_sup 创建 ranch_conns_sup 和 ranch_acceptors_sup
- ranch_acceptors_sup(启动NumAcceptors个ranch_acceptors监听listen_socket).
需要了解的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例子中,当有新的网络连接到来, 会通知ranch_conns_sup启动reverse_protocol, 而reverse_porotocol是gen_server行为, gen_server:start_link, 本质是调用proc_lib:start_link启动进程, 需要等到Mod:init调用完毕后, 才会给父进程发送子进程id,表示子进程启动完毕,但是在Mod:init中调用了 ranch:accept_ack, 子进程会处于一直等待shoot消息,而shoot消息需要reverse_protocol进程启动者 – ranch_conn_sup发送,但ranch_conn_sup又无法获取到reverse_protocol_pid,所以不能发送消息,两个进程处于互相等待状态 .
所以官方给出解决方法是 Mod:start_link函数体内,使用 proc_lib:spawn_link 启动reverse_protocol进程,该函数可以马上返回pid到父进程ranch_conn_sup, 而子进程调用Mod:init函数后,等待shoot消息到来,收到ranch_conn_sup发送的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文件头部可见.
网友评论