2013-03-25 66 views
1

以下代码适用于gen_tcp:connect()函数调用中的{packet,0}选项,但不适用于1,2和4(虽然我仅测试它为4,我假设1和2也不起作用)。我拥有的问题是为什么不这样做,重要的是使用一个在另一个之上?基本上Erlang文档没有提供关于数据包选项的详细说明,而Joe Armstrong编程Erlang也没有给出任何细节;他只是解释说数据包不是按顺序重组的,尽管我一直认为tcp数据包是在发送时收到的,与UDP不同。我有一个有趣的笔记是,this page上的客户端服务器有{packet,4}作为选项,它工作正常,它与下面的代码非常相似。下面的代码使用{packet,4}选项的服务器shell输出。Erlang:{packet,N}选项适用于N = 0但不是1,2,4?

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. 

回答

1

您的代码几乎是好的,只是修改环路(插座)行

情况下调用gen_tcp:recv的(插座, 6)的

通过

情况下调用gen_tcp:recv的(插座,0)

见文档:

的recv(插座,长度) - > {OK,分组} | {error,Reason} recv(Socket,Length,Timeout) - > {ok,Packet} | {error,Reason}

类型:Socket = socket()Length = integer()> = 0 Timeout = timeout() Packet = string()|二进制()| HttpPacket Reason =关闭| inet:posix()HttpPacket = term()请参阅 erlang:decode_packet/3中对HttpPacket的描述。

该函数从被动模式的套接字接收数据包。 A 关闭的套接字由返回值{error,closed}表示。

Length参数仅在套接字处于原始模式并且表示要读取的字节数时才有意义。如果长度= 0,则返回所有可用的字节,即 。如果长度> 0,则返回完全长度字节, 或错误;当套接字从另一侧关闭时,可能丢弃小于Length数据字节的数据。

可选的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. 
相关问题