这段程序一些地方参考:
写道
http://www.erlang.org/upload/klacke_examples/chargen.erl
依旧是erlang官网的一个example
自己独立写的时候 做了一个同步的版本 接下去改成异步
改成异步的时候没有把gen_tcp:listener那段独立到循环的进程中去
调用函数那段就运行完了(那么tcp的端口就相当于直接关闭了)
苦恼不已 后来按照以上程序在一些地方改了改 加上了 关闭 的操作
通过进程链接来关闭已经在服务的进程(就是一层的监督结构)
这边记点笔记,说说一些API调用之类的
代码如下:
-module(server). -export([start/0,start/1,loop_accept/2,listener/1]). -define(DEAFULT_PORT,1236). start() -> start(?DEAFULT_PORT). start(Port) -> spawn_link(?MODULE,listener,[Port]). listener(Port) -> case gen_tcp:listen(Port,[{active,false}]) of {ok,LSocket}-> process_flag(trap_exit,true), spawn_link(?MODULE,loop_accept,[LSocket,self()]), loop(LSocket); Other -> Other end. loop(LSocket) -> receive continue -> spawn_link(?MODULE,loop_accept,[LSocket,self()]), loop(LSocket); {stop,Reason} -> exit(Reason); stop -> exit(shutdown); Other -> io:format("link process exit:~p~n",[Other]), loop(LSocket) end. loop_accept(Ls,Pid) -> io:format("accept now~n"), case gen_tcp:accept(Ls) of {error, Reason} -> Pid ! {stop,Reason}; {ok,Socket} -> Pid ! continue,worker(Socket) end. worker(Socket) -> %%io:format("work now~n"), case gen_tcp:recv(Socket, 0) of {ok, Packet} -> gen_tcp:send(Socket,Packet),worker(Socket); {error, Reason} -> %%io:format("Socket ~w closed [~w]~w",[Socket,self(),Reason]), exit(Reason) end.
代码的基本流程很简单:
- server:start/0或/1启动应用
- 产生并连接进程sub(监督者进程 同时用来监视进行echo的进程的情况)
- sub用来启动监听的进程acc(该进程一启动就会监听 有连接进来给work处理)
- sub接受到退出信息(stop)后就退出并发送shutdown信息 其他的acc进程也跟着退出
代码说明:
listen时使用了active,false的参数 说明所有进来的信息要通过gen_tcp:recv/2才能获取到(而 active,true或者 active,once则会直接把信息传送给进程 区别是后者只传送一次(所以在接受时要通过inet:setopts/2不断重置为{active,once})
此外设置成 active,false 接受的消息要么是{ok,内容} 要么是{error,Reason}
而其他两种收到的形式是 {tcp,S,Data}和 {tcp_closed,S}(那个S就是通信用的Socket)
附带一张 链接时退出信号传播时的对应表现:
捕获状态 退出信号(原因) 动作
true kill 消亡,向链接的进程广播退出信号(killed)
true X 将{'EXIT', Pid, X} 加入到邮箱
false normal 不做任何事
false kill 消亡,向链接的进程广播退出信号(killed)
false X 消亡,向链接的进程广播退出信号X
该表来源:
http://www.cnblogs.com/fangjie008/archive/2012/08/28/2660361.html
捕获指的是process_flag(trap_exit,true).