2013-03-25 42 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. 
相關問題