基于TCP的RPC服务

TCP服务器上的RPC,通过创建一个服务器进程监听传入的tcp连接,并允许用户 通过此TCP流执行RPC命令

Erlang 复制代码
-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端口创建一个连接。

相关推荐
qinyia27 分钟前
WisdomSSH解决NFS服务因“RPC fragment too large“导致的性能警告
网络·网络协议·rpc
SoleMotive.34 分钟前
http和rpc的区别
网络协议·http·rpc
rainmanqqst7 小时前
C#Netcore支持Https
网络协议·http·https·c#
_星辰大海乀7 小时前
IP 协议
服务器·网络·tcp/ip·nat·子网掩码·ip协议
rising start10 小时前
三、FastAPI :POST 请求、用户接口设计与 Requests 测试
python·网络协议·http·fastapi
6***v41711 小时前
windows手动配置IP地址与DNS服务器以及netsh端口转发
服务器·windows·tcp/ip
老蒋新思维13 小时前
创客匠人 2025 峰会深度解析:AI 赋能垂直领域,创始人 IP 变现的差异化路径
大数据·网络·人工智能·网络协议·tcp/ip·重构·知识付费
北京耐用通信13 小时前
耐达讯自动化Profibus光纤转换器为您的水处理系统装上“光纤高速路”,数据从此畅通无阻!
网络·人工智能·科技·网络协议·自动化·信息与通信
老蒋新思维13 小时前
创客匠人 2025 峰会深度解析:AI 激活创始人 IP 变现的核心价值
网络·人工智能·网络协议·tcp/ip·创始人ip·创客匠人·知识变现
傲世(C/C++,Linux)14 小时前
Linux系统编程——TCP客户端
linux·运维·tcp/ip