Erlang:{packet,N}选项适用于N = 0,但不适用于1、2、4?

qco9c6ql  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(168)

以下代码适用于gen_tcp:connect()函数调用中的{packet,0}选项,第2和第4段(虽然我只测试了4,我假设1和2也不工作)。我的问题是为什么不,使用一个比另一个重要吗?基本上,Erlang文档并没有对有关数据包选项的主题进行详细的解释,Joe Armstrong的Programming 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.
nr9pn0ug

nr9pn0ug1#

你的代码差不多就可以了,只是在循环(Socket)中修改了行
case gen_tcp:接收(套接字,6)属于

case gen_tcp:接收(套接字,0)属于
请参阅文档:

    • recv(套接字,长度)-〉{正常,数据包}| {错误,原因} recv(套接字,长度,超时)-〉{正常,数据包}| {错误,原因}**

类型:套接字=套接字()长度=整数()〉= 0超时=超时()数据包=字符串()|二进制()|HttpPacket原因=已关闭|请参阅erlang:decode_packet/3中对HttpPacket的描述。
此函数用于在被动模式下接收来自套接字的数据包。如果套接字已关闭,则返回值为{error,closed}。

    • Length参数只有在套接字处于原始模式时才有意义,并且表示要读取的字节数。如果Length = 0,**则返回所有可用字节。如果Length〉0,则返回正好Length字节,否则返回错误。当套接字从另一端关闭时,可能丢弃小于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.

相关问题