erlang tcp服务器和客户端的简单实现

来源:互联网 发布:js实现div隐藏显示 编辑:程序博客网 时间:2024/05/16 01:24

看了《erlang程序设计》的lib_chan代码,自己也试着写了一个,不过大部分代码都摘自lib_chan,做了一个改编。

-module(lib_comm).-export([start_server/1, stop_server/1, start_client/2, send/2]).stop_server(Port) when is_integer(Port) ->    ServerName = list_to_atom("portServer" ++ integer_to_list(Port)),    case whereis(ServerName) ofundefined ->    not_started;Pid ->    exit(Pid, kill),    (catch unregister(ServerName)),    stopped    end.start_server(Port) ->io:format("start_server(), Pid: ~p~n", [self()]),spawn(fun() -> start_port_server(Port) end).start_port_server(Port) ->io:format("start_port_server(), Pid: ~p~n", [self()]),start_raw_server(Port, fun(Socket) -> start_port_instance(Socket) end, 100, 4).start_raw_server(Port, Fun, Max, PacketLength) ->io:format("start_raw_server(), Pid: ~p~n", [self()]),ServerName = list_to_atom("portServer" ++ integer_to_list(Port)),case whereis(ServerName) ofundefined ->Self = self(),Pid = spawn_link(fun() -> cold_start(Self,Port,Fun,Max,PacketLength) end),receive{Pid, ok} ->register(ServerName, Pid),{ok, self()};{Pid, Error} ->Errorend;_Pid ->    {error, already_started}    end.cold_start(Master,Port,Fun,Max,PacketLength) ->io:format("cold_start(), Pid: ~p~n", [self()]),process_flag(trap_exit, true),io:format("Starting a port server on ~p...~n",[Port]),case gen_tcp:listen(Port, [binary, {nodelay,true}, {packet, PacketLength}, {reuseaddr, true}, {active, true}]) of{ok, Listen} ->io:format("Listening to:~p~n",[Listen]),Master ! {self(), ok},_New = start_accept(Listen, Fun),io:format("New 1 : ~p~n", [_New]),    socket_loop(Listen, Master, [], Fun, Max);Error ->Master ! {self(), Error}end.start_accept(Listen, Fun) ->    S = self(),    spawn_link(fun() -> start_child(S, Listen, Fun) end).start_child(Parent, Listen, Fun) ->io:format("Pid: ~p gen_tcp:accept ~n", [self()]),case gen_tcp:accept(Listen) of{ok, Socket} ->io:format("Pid: ~p accepted ~n", [self()]),Parent ! {istarted, self()},    % tell the controllerinet:setopts(Socket, [ {packet,4}, binary, {nodelay,true}, {active, true}]), io:format("running the child:~p Fun=~p~n", [Socket, Fun]),process_flag(trap_exit, true),case (catch Fun(Socket)) of{'EXIT', normal} ->    true;{'EXIT', Why} ->    io:format("Port process dies with exit:~p~n",[Why]),    true;_ ->     true %% not an exit so everything's ok    endend.socket_loop(Listen, Master, Active, Fun, Max) ->receive{istarted, Pid} ->io:format("Pid = ~p istarted ~n", [Pid]),    Active1 = [Pid|Active],    possibly_start_another(Master, Listen,Active1,Fun,Max);    {'EXIT', Master, _Why} ->    io:format("Pid = ~p master exit, reason: ~p ~n", [Master, _Why]),    socket_loop(Listen, Master, Active, Fun, Max);    {'EXIT', Pid, _Why} ->    io:format("Pid = ~p exit, reason: ~p ~n", [Pid, _Why]),    Active1 = lists:delete(Pid, Active),    possibly_start_another(Master, Listen,Active1,Fun,Max);    _Other ->    io:format("socket_loop() _Other = ~p~n", [_Other]),    socket_loop(Listen, Master, Active, Fun, Max)end.possibly_start_another(Master, Listen, Active, Fun, Max) ->    case length(Active) ofN when N < Max ->    _New = start_accept(Listen, Fun),    io:format("New 2: ~p~n", [_New]),    socket_loop(Master, Listen, Active, Fun,Max);_ ->    socket_loop(Master, Listen, Active, Fun, Max)    end.start_port_instance(Socket) ->process_flag(trap_exit, true),MessageHandler = spawn_link(fun() -> start_server_biz() end),message_loop(Socket, MessageHandler).start_server_biz() ->server_biz_loop().server_biz_loop() ->receive{recv, Pid, Term} ->io:format("server recv message ~p~n", [Term]),Pid ! {send, Term},server_biz_loop();{closed, Pid} ->Pid ! closeend.message_loop(Socket, Pid) ->receive{tcp, Socket, Bin} ->    Term = binary_to_term(Bin),    Pid ! {recv, self(), Term},    message_loop(Socket, Pid);{tcp_closed, Socket} ->    Pid ! {closed, self()};{'EXIT', Pid, _Why} ->    gen_tcp:close(Socket);close ->    gen_tcp:close(Socket);{send, Term}  ->    gen_tcp:send(Socket, term_to_binary(Term)),    message_loop(Socket, Pid);UUg ->    io:format("protocol error:~p~n",[UUg]),    message_loop(Socket, Pid)    end.start_client(Host, Port) ->Self = self(),spawn(fun() -> start_raw_client(Self, Host, Port) end),receive{ok, Pid} ->Pid;Error ->io:format("client connect failure, ~p~n", [Error]),Errorend.start_raw_client(Master, Host, Port) ->PacketLength = 4,Self = self(),Pid = spawn(fun() -> connect(Self, Host, Port, PacketLength) end),client_biz_loop(Master, Pid).connect(Parent, Host, Port, PacketLength) ->case gen_tcp:connect(Host, Port, [binary, {active, true}, {packet, PacketLength}]) of{ok, Socket} ->    Parent ! {ok, self()},    message_loop(Socket, Parent);Error ->    Parent ! {self(), Error}end.client_biz_loop(Master, Pid) ->receive{ok, Pid} ->Pid ! {send, "hello world"},Master ! {ok, Pid},client_biz_loop(Master, Pid);{recv, Pid, Term} ->io:format("client recv message: ~p~n", [Term]),client_biz_loop(Master, Pid);Error ->Master ! Error,Errorend.send(Pid, Term) -> Pid ! {send, Term}.    
按照下面方式调用:

lib_comm:start_server(8080).

Pid = lib_comm:start_client("localhost", 8080).

lib_comm:send(Pid, "aaaaa").

0 0
原创粉丝点击