以下代码适用于{packet,0}
函数调用中的gen_tcp:connect()
选项,但不适用于1,2和4(尽管我只测试了4,我假设1和2不是也不工作)。我的问题是为什么不是,并且重要的是使用一个而不是另一个?基本上,Erlang文档没有详细解释有关数据包选项的主题,而Joe Armstrong编写的Erlang也没有提供任何重要细节;他只是解释了数据包没有按顺序重新组装,尽管我总是认为tcp数据包在发送时会被接收,这与UDP不同。我有一个有趣的注意事项是this page上的客户端服务器有{packet,4}
作为选项,它工作正常,它与下面的代码非常相似。下面是代码中使用的{packet,4}
选项的服务器shell输出。
Erlang R16A (erts-5.10) [smp:8:8] [async-threads:10]
Eshell V5.10 (abort with ^G)
1> cd("c:/erlang").
c:/erlang
ok
2> c(cp3).
{ok,cp3}
3> cp3:server().
Started Server:
<0.41.0>
Accept Server:
Pid <0.43.0>
Connection accepted
Accept Server:
Loop Server:
Error on socket #Port<0.2256> reason: einval
这是客户端shell输出。
Erlang R16A (erts-5.10) [smp:8:8] [async-threads:10]
Eshell V5.10 (abort with ^G)
1> cd("c:/erlang").
c:/erlang
ok
2> cp3:client().
exit
3>
这是使用的代码,
-module(cp3).
-export([client/0, server/0,start/0,accept/1,enter_loop/1,loop/1]).
client() ->
{ok, Socket} = gen_tcp:connect("localhost", 4001,[binary, {packet, 4}]),
ok = gen_tcp:send(Socket, "packet"),
receive
{tcp,Socket,String} ->
io:format("Client received = ~p~n",[String]),
io:format("Client result = ~p~n",[String]),
gen_tcp:close(Socket)
after 1000 ->
exit
end.
server() ->
Pid = spawn(fun()-> start() end),
Pid.
start() ->
io:format("Started Server:~n"),
{ok, Socket} = gen_tcp:listen(4001, [binary, {packet, 4},{reuseaddr, true},{active, false}]),
accept(Socket).
accept(ListenSocket) ->
io:format("Accept Server:~n"),
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
Pid = spawn(fun() ->
io:format("Connection accepted ~n", []),
enter_loop(Socket)
end),
io:format("Pid ~p~n",[Pid]),
gen_tcp:controlling_process(Socket, Pid),
Pid ! ack,
accept(ListenSocket);
Error ->
exit(Error)
end.
enter_loop(Socket) ->
%% make sure to acknowledge owner rights transmission finished
receive ack -> ok end,
loop(Socket).
loop(Socket) ->
io:format("Loop Server:~n"),
case gen_tcp:recv(Socket, 6) of
{ok, Data} ->
case Data of
<<"packet">> ->
io:format("Server replying = ~p~n",[Data]),
gen_tcp:send(Socket, Data),
loop(Socket)
end;
{error, Reason} ->
io:format("Error on socket ~p reason: ~p~n", [Socket, Reason])
end.
答案 0 :(得分:1)
您的代码几乎可以,只需在循环中修改(Socket)行
案例gen_tcp:recv(插座,6)
通过
案例gen_tcp:recv(套接字,0)
见文档:
recv(插座,长度) - &gt; {ok,Packet} | {error,Reason} recv(套接字,长度,超时) - &gt; {ok,Packet} | {错误,原因}
类型:Socket = socket()长度=整数()&gt; = 0超时=超时() Packet = string()| binary()| HttpPacket Reason =关闭| inet:posix()HttpPacket = term()参见HttpPacket的描述 二郎:decode_packet / 3
此函数从被动模式下的套接字接收数据包。一个 closed socket由返回值{error,closed}表示。
长度参数仅在套接字处于原始模式时有意义,并表示要读取的字节数。如果长度= 0, 返回所有可用字节。如果长度> 0,返回正确的长度字节, 或错误;可能会丢弃少于长度的数据字节 套接字从另一边关闭。
可选的Timeout参数指定超时(以毫秒为单位)。 默认值为无穷大。
通过这个修改它可以工作,但是当客户端在每次调用后关闭套接字时,会收到一条错误消息,我不确定从客户端关闭套接字是否有用。您可以通过以下方式修改客户端来更改此行为:
client() ->
{ok, Socket} = gen_tcp:connect("localhost", 4001,[binary, {packet, 4}]),
ok = gen_tcp:send(Socket, "packet"),
receive
{tcp,Socket,String} ->
io:format("Client received = ~p~n",[String]),
io:format("Client result = ~p~n",[String])
%gen_tcp:close(Socket)
after 1000 ->
exit
end.