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

Tcp Erlang:{packet,N}选项适用于N=0,但不适用于1,2,4?,tcp,erlang,client-server,option,packet,Tcp,Erlang,Client Server,Option,Packet,以下代码确实适用于gen_tcp:connect()函数调用中的{packet,0}选项,但不适用于1、2和4(尽管我只测试了4,并且假设1和2也不起作用)。我的问题是为什么不这样做,使用其中一个是否重要?基本上,Erlang文档没有详细解释关于包选项的主题,Joe Armstrong编写的Erlang编程也没有给出任何详细信息;他只是解释说,数据包没有按顺序重新组装,尽管我一直认为tcp数据包在发送时会被接收,不像UDP。我有一个有趣的注意事项,就是上的客户机服务器有{packet,4}作为选

以下代码确实适用于
gen_tcp:connect()
函数调用中的
{packet,0}
选项,但不适用于1、2和4(尽管我只测试了4,并且假设1和2也不起作用)。我的问题是为什么不这样做,使用其中一个是否重要?基本上,Erlang文档没有详细解释关于包选项的主题,Joe Armstrong编写的Erlang编程也没有给出任何详细信息;他只是解释说,数据包没有按顺序重新组装,尽管我一直认为tcp数据包在发送时会被接收,不像UDP。我有一个有趣的注意事项,就是上的客户机服务器有
{packet,4}
作为选项,它工作正常,与下面的代码非常相似。这是下面代码中使用的
{packet,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
这是使用的代码

-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.
-模块(cp3)。
-导出([client/0、server/0、start/0、accept/1、enter\u loop/1、loop/1])。
客户端()->
{ok,Socket}=gen_tcp:connect(“localhost”,4001,[二进制,{packet,4}]),
ok=gen_tcp:send(套接字,“数据包”),
接收
{tcp,套接字,字符串}->
io:格式(“客户端接收=~p~n”,[String]),
io:format(“客户端结果=~p~n,[String]),
gen_tcp:关闭(套接字)
1000后->
出口
结束。
服务器()->
Pid=spawn(fun()->start()end),
Pid。
开始()->
io:格式(“已启动服务器:~n”),
{ok,Socket}=gen_tcp:listen(4001[binary,{packet,4},{reuseaddr,true},{active,false}]),
接受(套接字)。
接受(ListenSocket)->
io:格式(“接受服务器:~n”),
案例gen_tcp:accept(ListenSocket)的
{好的,套接字}->
Pid=繁殖(乐趣()->
io:格式(“已接受连接~n”,[]),
输入循环(套接字)
(完),,
io:格式(“Pid~p~n,[Pid]),
gen_tcp:控制进程(套接字、Pid),
Pid!阿克,
接受(ListenSocket);
错误->
退出(错误)
结束。
输入_循环(套接字)->
%%确保确认所有者权利传输已完成
接收确认->确定结束,
回路(插座)。
循环(套接字)->
io:格式(“循环服务器:~n”),
案例gen_tcp:recv(插座,6)的
{好的,数据}->
案例数据
->                 
io:format(“服务器应答=~p~n,[Data]),
gen_tcp:发送(套接字、数据),
回路(插座)
结束;
{错误,原因}->
io:format(“套接字上的错误~p原因:~p~n”,[socket,原因])
结束。

您的代码基本正常,只需在循环(套接字)行中修改即可

案例gen_tcp:recv(插座,6)的

案例gen_tcp:recv(套接字,0)的

见文件:

recv(套接字,长度)->{ok,Packet}{error,Reason}recv(套接字,长度,超时)->{ok,Packet}{error,Reason}

类型:套接字=套接字()长度=整数()>=0超时=超时() Packet=string()| binary()| HttpPacket原因=关闭| inet:posix()HttpPacket=term()请参阅中的HttpPacket说明 erlang:解码数据包/3

此函数在被动模式下从套接字接收数据包。A. 闭合套接字由返回值{error,closed}表示

只有当套接字处于原始模式并表示要读取的字节数时,Length参数才有意义。如果长度=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.

您的代码基本正常,只需在循环(套接字)行中修改即可

案例gen_tcp:recv(插座,6)的

案例gen_tcp:recv(套接字,0)的

见文件:

recv(套接字,长度)->{ok,Packet}{error,Reason}recv(套接字,长度,超时)->{ok,Packet}{error,Reason}

类型:套接字=套接字()长度=整数()>=0超时=超时() Packet=string()| binary()| HttpPacket原因=关闭| inet:posix()HttpPacket=term()请参阅中的HttpPacket说明 erlang:解码数据包/3

此函数在被动模式下从套接字接收数据包。A. 闭合套接字由返回值{error,closed}表示

只有当套接字处于原始模式并表示要读取的字节数时,Length参数才有意义。如果长度=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.