亿图图示和Erlang:一个套接字应用程序
发布日期:2021-06-29 17:24:21 浏览次数:2 分类:技术文章

本文共 8278 字,大约阅读时间需要 27 分钟。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

-module(lib_chan).

-export([cast/2,start_server/0,start_server/1,connect/5,disconnect/1,rpc/2]).
-import(lists,[map/2,member/2,foreach/2]).
-import(lib_chan_mm,[send/2,close/1]).

start_server()->

case os:getenv(“HOME”) of
false->
exit({ebadEnv,“HOME”});
Home->
start_server(Home++"./erlang_config/lib_chan.conf")
end.
start_server(ConfigFile)->
io:format(“lib_chan starting:pn”,[ConfigFile]),
case file:consult(ConfigFile) of
{ok,ConfigData}->
io:format(“ConfigData=pn”,[ConfigData]),
case check_terms(ConfigData) of
[]->
start_server1(ConfigData);
Errors->
exit({eDaemonConfig,Errors})
end;
{error,Why}->
exit({eDaemonConfig,Why})
end.
check_terms(ConfigData)->
L=map(fun check_term/1,ConfigData),
[X||{error,X}<-L].
check_term({port,P}) when is_integer§->ok;
check_term({service,,password,,mfa,,,})->ok;
check_term(X)->{error,{badTerm,X}}.
start_server1(ConfigData)->register(lib_chan,spawn(fun()->start_server2(ConfigData) end)).
start_server2(ConfigData)->
[Port]=[P||{port,P}<-ConfigData],
start_port_server(Port,ConfigData).
start_port_server(Port,ConfigData)->
lib_chan_cs:start_raw_server(Port,
fun(Socket)->
start_port_instance(Socket,ConfigData) end,
100,
4).
start_port_instance(Socket,ConfigData)->
S=self(),
Controller=spawn_link(fun()->start_erl_port_server(S,ConfigData) end),
lib_chan_mm:loop(Socket,Controller).
start_erl_port_server(MM,ConfigData)->
receive
{chan,MM,{startService,Mod,ArgC}}->
case get_service_definition(Mod,ConfigData) of
{yes,Pwd,MFA}->
case Pwd of
none ->
send(MM,ack),
really_start(MM,ArgC,MFA);
->
do_authentication(Pwd,MM,ArgC,MFA)
end;
no->
io:format(“sending bad service~n”),
send(MM,badService),
close(MM)
end;
Any->
io:format("*** Erl port server got:~p pn",[MM,Any]),
exit({protocolViolation,Any})
end.
do_authentication(Pwd,MM,Argc,MFA)->
C=lib_chan_auth:make_chanllenge(),
send(MM,{chanllenge,C}),
receive
{chan,MM,{response,R}}->
case lib_chan_auth:is_response_correct(C,R,Pwd) of
true->
send(MM,ack),
really_start(MM,Argc,MFA);
false->
send(MM,authFail),
close(MM)
end
end.
really_start(MM,ArgC,{Mod,Func,ArgS})->
case(catch apply(Mod,Func,[MM,ArgC,ArgS])) of
{‘EXIT’,normal}->true;
{‘EXIT’,Why}->
io:format(“server error:pn”,[Why]);
Why->
io:format(“server error should die with exit(normal) was:pn”,[Why])
end.
get_service_definition(Mod,[{service,Mod,password,Pwd,mfa,M,F,A}|
])->
{yes,Pwd,{M,F,A}};
get_service_definition(Name,[
|T])->
get_service_definition(Name,T);
get_service_definition(_,[])->
no.
connect(Host,Port,Service,Secret,ArgC)->
S=self(),
MM=spawn(fun()->connect(S,Host,Port) end),
receive
{MM,ok}->
case authenticate(MM,Service,Secret,ArgC) of
ok->{ok,MM};
Error->Error
end;
{MM,Error}->
Error
end.
connect(Parent,Host,Port)->
case lib_chan_cs:start_newclient(Host,Port,4)of
{ok,Socket}->
Parent!{self(),ok},
lib_chan_mm:loop(Socket,Parent);
Error->
Parent!{self(),Error}
end.
authenticate(MM,Service,Secret,ArgC)->
send(MM,{startService,Service,ArgC}),
receive
{chan,MM,ack}->
ok;
{chan,MM,{challenge,C}}->
R=lib_chan_auth:make_response(C,Secret),
send(MM,{response,R}),
receive
{chan,MM,ack}->
ok;
{chan,MM,authFail}->
wait_close(MM),
{error,authFail};
Other->
{error,Other}
end;
{chan,MM,badService}->
wait_close(MM),
{error,badService};
Other->
{error,Other}
end.
wait_close(MM)->
receive
{chan_closed,MM}->
true
after 5000->
io:format("**error lib_chan~n"),
true
end.
disconnect(MM)->close(MM).
rpc(MM,Q)->
send(MM,Q),
receive
{chan,MM,Reply}->
Reply
end.
cast(MM,Q)->
send(MM,Q).

-module(mod_math).

-export([run/3]).
run(MM,ArgC,ArgS)->
io:format(“mod_math:run starting ~n”
“ArgC=~p ArgS=pn”,[ArgC,ArgS]),
loop(MM).
loop(MM)->
receive
{chan,MM,{factorial,N}}->
MM!{send,fac(N)},
loop(MM);
{chan,MM,{fibonacci,N}}->
MM!{send,fib(N)},
loop(MM);
{chan_closed,MM}->
io:format(“mod_math stopping ~n”),
exit(normal)
end.
fac(0)->1;
fac(N)->N*fac(N-1).
fib(1)->1;
fib(2)->1;
fib(N)->fib(N-1)+fib(N-2).

-module(lib_chan_cs).

-export([start_raw_server/4,start_raw_client/3]).
-export([stop/1]).
-export([children/1]).
start_raw_client(Host,Port,PacketLength)->
gen_tcp:connect(Host,Port,[binary,{active,true},{packet,PacketLength}]).

start_raw_server(Port,Fun,Max,PacketLength)->

Name = port_name(Port),
case whereis(Name) of
undefined->
Self = self(),
Pid = spawn_link(fun()->
cold_start(Self,Port,Fun,Max,PacketLength)
end),
receive
{Pid,ok}->
register(Name,Pid),
{ok,self()};
{Pid,Error}->
Error
end;
_Pid->
{error,already_started}
end.

stop(Port) when is_integer(Port)->

Name = port_name(Port),
case whereis(Name) of
undefined->
not_started;
Pid->
exit(Pid,kill),
(catch unregister(Name)),
stopped
end.
children(Port) when is_integer(Port)->
port_name(Port)!{children,self()},
receive
{session_server,Reply}->Reply
end.
port_name(Port) when is_integer(Port)->
list_to_atom(“portserver”++integer_to_list(Port)).
cold_start(Master,Port,Fun,Max,PacketLength)->
process_flag(trap_exit,true),
case gen_tcp:listen(Port,[binary,
{nodelay,true},
{packet,PacketLength},
{reuseaddr,true},
{active,true}]) of
{ok,Listen}->
Master!{self(),ok},
New=start_accept(Listen,Fun),
socket_loop(Listen,New,[],Fun,Max);
Error->
Master!{self(),Error}
end.
socket_loop(Listen,New,Active,Fun,Max)->
receive
{istarted,New}->
Active1=[New|Active],
possibly_start_another(false,Listen,Active1,Fun,Max);
{‘EXIT’,New,_Why}->
possibly_start_another(false,Listen,Active,Fun,Max);
{‘EXIT’,Pid,_Why}->
Active1=lists:delete(Pid,Active),
possibly_start_another(New,Listen,Active1,Fun,Max);
{children,From}->
From!{session_server,Active},
socket_loop(Listen,New,Active,Fun,Max);
_Other->
socket_loop(Listen,New,Active,Fun,Max)
end.
possibly_start_another(New,Listen,Active,Fun,Max)
when is_pid(New)->
socket_loop(Listen,New,Active,Fun,Max);
possibly_start_another(false,Listen,Active,Fun,Max)->
case length(Active) of
N when N < Max ->
New = start_accept(Listen,Fun),
socket_loop(Listen,New,Active,Fun,Max);
_->
socket_loop(Listen,false,Active,Fun,Max)
end.
start_accept(Listen,Fun)->
S=self(),
spawn_link(fun()->start_child(S,Listen,Fun)end).
start_child(Parent,Listen,Fun)->
case gen_tcp:accept(Listen) of
{ok,Socket}->
Parent!{istarted,self()},
inet:setopts(Socket,[{packet,4},
binary,{nodelay,true},
{active,true}]),
process_flag(trap_exit,true),
case(catch Fun(Socket)) of
{‘EXIT’,normal}->
true;
{‘EXIT’,Why}->
io:format(“port process dies with exit:pn”,[Why]),
true;
_->
true
end
end.
configur1.txt如下
{port,2233}.
{service,math,password,“qwerty”,mfa,mod_math,run,[]}.
在这里插入图片描述
-module(lib_chan_mm).
-export([loop/2,send/2,close/1,controller/2,set_trace/2,trace_with_tag/2]).
send(Pid,Term)->Pid!{send,Term}.
close(Pid)->Pid!close.
controller(Pid,Pid1)->Pid!{setController,Pid1}.
set_trace(Pid,X)->Pid!{trace,X}.
trace_with_tag(Pid,Tag)->
set_trace(Pid,{true,fun(Msg)->io:format(“MM:~p pn”,[Tag,Msg])
end}).

loop(Socket,Pid)->

process_flag(trap_exit,true),
loop1(Socket,Pid,false).
loop1(Socket,Pid,Trace)->
receive
{tcp,Socket,Bin}->
Term=binary_to_term(Bin),
trace_it(Trace,{socketReceived,Term}),
Pid!{chan,self(),Term},
loop1(Socket,Pid,Trace);
{tcp_closed,Socket}->
trace_it(Trace,socketClosed),
Pid!{chan_closed,self()};
{‘EXIT’,Pid,Why}->
trace_it(Trace,{controllingProcessExit,Why}),
gen_tcp:close(Socket);
{setController,Pid1}->
trace_it(Trace,{changedController,Pid}),
loop1(Socket,Pid1,Trace);
{trace,Trace1}->
trace_it(Trace,{setTrace,Trace1}),
loop1(Socket,Pid,Trace1);
close->
trace_it(Trace,closedByClient),
gen_tcp:close(Socket);
{send,Term}->
trace_it(Trace,{sendingMessage,Term}),
gen_tcp:send(Socket,term_to_binary(Term)),
loop1(Socket,Pid,Trace);
UUg->
io:format(“lib_chan_mm:protocol error:pn”,[UUg]),
loop1(Socket,Pid,Trace)
end.
trace_it(false,_)->void;
trace_it({trye,F},M)->F(M).

-module(lib_chan_auth).

-export([make_challenge/0,make_response/2,is_response_correct/3]).
make_challenge()->
random_string(25).
make_response(Challenge,Secret)->
lib_md5:string(Challenge++Secret).
is_response_correct(Challenge,Response,Secret)->
case lib_md5:string(Challenge++Secret) of
Response->true;
_ ->false
end.
random_string(N)->random_seed(),random_string(N,[]).
random_string(0,D)->D;
random_string(N,D)->
random_string(N-1,[random:uniform(26)-1+$a|D]).
random_seed()->
{
,,X}=erlang:now(),
{H,M,S}=time(),
H1=HX rem 32767,
M1=M
X rem 32767,
S1=S*X rem 32767,
put(random_seed,{H1,M1,S1}).

在这里插入图片描述

Erlang程序设计(第2版)------【瑞典】Joe Armstrong著 牛化成译

转载地址:https://blog.csdn.net/m0_38127487/article/details/113772321 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Ruby中式编程之线程二及代码行级优化
下一篇:亿图图示组件简介和箱子计算面积及代码行级优化

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月26日 20时55分53秒