TCP服务器上的RPC,通过创建一个服务器进程监听传入的tcp连接,并允许用户 通过此TCP流执行RPC命令
- -module(tr_server).
- -author("chen").
- -behaviour(gen_server).
-
- %% API
- -export([
- start_link/1,
- start_link/0,
- get_count/0,
- stop/0
- ]).
-
- -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
-
- -define(SERVER, ?MODULE).
- -define(DEFAULT_PORT, 8000).
-
- -record(state, {port, lsock, request_count = 0}).
-
- start_link(Port) ->
- gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []).
-
- start_link() ->
- start_link(?DEFAULT_PORT).
- get_count() ->
- gen_server:call(?SERVER, get_count).
- stop() ->
- gen_server:cast(?SERVER, stop).
-
- init([Port]) ->
- {ok, LSock} = gen_tcp:listen(Port, [{active, true}]),
- {ok, #state{port = Port, lsock = LSock}, 0}.
-
- handle_call(get_count, _From, State) ->
- {reply, {ok, State#state.request_count}, State}.
-
- handle_cast(stop, State) ->
- {stop, normal, State}.
-
- handle_info({tcp, Socket, RawData}, State) ->
- do_rpc(Socket, RawData),
- RequestCount = State#state.request_count,
- {noreply, State#state{request_count = RequestCount + 1}};
- handle_info(timeout, #state{lsock = LSock} = State) ->
- {ok, _Sock} = gen_tcp:accept(LSock),
- {noreply, State}.
-
- terminate(_Reason, _State) ->
- ok.
-
- code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
- do_rpc(Socket, RawData) ->
- try
- {M, F, A} = split_out_mfa(RawData),
- Result = apply(M, F, A),
- gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
- catch
- _Class:Err ->
- gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
- end.
-
- split_out_mfa(RawData) ->
- MFA = re:replace(RawData, "\r\n$", "", [{return, list}]),
- {match, [M, F, A]} =
- re:run(MFA,
- "(.*):(.*)\s*\\((.*)\s*\\)\s*.\s*$",
- [{capture, [1,2,3], list}, ungreedy]),
- {list_to_atom(M), list_to_atom(F), args_to_terms(A)}.
-
- args_to_terms(RawArgs) ->
- {ok, Toks, _Line} = erl_scan:string("[" ++ RawArgs ++ "]. ", 1),
- {ok, Args} = erl_parse:parse_term(Toks),
- Args.
处理TCP上的RPC请求
do_rpc(Socket, RawData) ->
try
{M, F, A} = split_out_mfa(RawData),
Result = apply(M, F, A),
gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
catch
_Class:Err ->
gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
end.
在 split_out_mfa(RawData)中,解析请求数据,随后,将模块名、函数名、参数项式列表传给内置函数apply/,执行请求中的调用。最后,该函数的返回值由io_lib:fwrite/2转换为格式化文本,用作回传给用户的响应,通过套接字发送回去。
split_out_mfa(RawData) ->
MFA = re:replace(RawData, "\r\n$", "", [{return, list}]),
{match, [M, F, A]} =
re:run(MFA,
"(.*):(.*)\s*\\((.*)\s*\\)\s*.\s*$",
[{capture, [1,2,3], list}, ungreedy]),
{list_to_atom(M), list_to_atom(F), args_to_terms(A)}.
在 split_out_mfa(RawData)中,解析请求中的字符串。

利用xshell向8000端口创建一个连接。
