客户端在发送消息后关闭,为什么gen_tcp和opts{active,false}接受两次
我只是用gen_tcp做了一个测试。一个简单的echo服务器和一个客户端 但客户端启动并关闭,服务器接受两个连接,一个正常,另一个坏 我的演示脚本有什么问题吗?如何解释 服务器客户端在发送消息后关闭,为什么gen_tcp和opts{active,false}接受两次,tcp,network-programming,erlang,gen-tcp,Tcp,Network Programming,Erlang,Gen Tcp,我只是用gen_tcp做了一个测试。一个简单的echo服务器和一个客户端 但客户端启动并关闭,服务器接受两个连接,一个正常,另一个坏 我的演示脚本有什么问题吗?如何解释 服务器 -模块(echo)。 -导出([listen/1])。 -定义(TCP_选项,[二进制,{packet,0},{active,false},{reuseaddr,true}])。 监听(端口)-> {ok,LSocket}=gen_tcp:listen(端口,tcp_选项), 接受(LSocket)。 接受(LSocke
-模块(echo)。
-导出([listen/1])。
-定义(TCP_选项,[二进制,{packet,0},{active,false},{reuseaddr,true}])。
监听(端口)->
{ok,LSocket}=gen_tcp:listen(端口,tcp_选项),
接受(LSocket)。
接受(LSocket)->
{ok,Socket}=gen_tcp:accept(LSocket),
繁殖(fun()->循环(套接字)结束),
接受(LSocket)。
循环(套接字)->
计时器:睡眠(10000),
P=inet:peername(插座),
io:格式(“ok~p~n,[p]),
案例gen_tcp:recv(套接字,0)的
{好的,数据}->
gen_tcp:发送(套接字、数据),
回路(插座);
{错误,已关闭}->
好啊
E->
io:格式(“错误的~p~n”,[E])
结束。
演示服务器
1>c(echo)。
{好的,回声}
2> 回声:听(1111)。
好{好{192168,2184},51608}
ok{错误,enotconn}
客户
>spawn(fun()->{ok,P}=gen_-tcp:connect(“192.168.2.173”,1111,[]),gen_-tcp:send(P,“aa”),gen_-tcp:close(P)end)。
```
但客户端启动并关闭,服务器接受两个连接,一个正常,另一个坏
实际上,您的服务器只接受一个连接:
loop/1
inet:peername/1
返回{ok,{{192168,2184},51608}}
,因为套接字仍然打开gen\u tcp:recv/2
返回客户端发送的
gen_tcp:send/2
将数据从3发送到客户端loop/1
inet:peername/1
返回{error,enotconn}
,因为客户端关闭了套接字genu-tcp:recv/2
返回{error,closed}
-模块(echo)。
-导出([listen/1])。
-定义(TCP_选项,[二进制,{packet,0},{active,false},{reuseaddr,true}])。
监听(端口)->
{ok,LSocket}=gen_tcp:listen(端口,tcp_选项),
接受(LSocket)。
接受(LSocket)->
{ok,CSocket}=gen_tcp:accept(LSocket),
Ref=make_Ref(),
To=spawn(fun()->init(Ref,CSocket)end),
gen_tcp:控制进程(CSocket,To),
到{切换,Ref,CSocket},
接受(LSocket)。
初始化(参考,套接字)->
接收
{切换,Ref,Socket}->
{ok,Peername}=inet:Peername(套接字),
io:格式(“[S]peername~p~n”,[peername]),
回路(插座)
结束。
循环(套接字)->
案例gen_tcp:recv(套接字,0)的
{好的,数据}->
io:格式(“[S]得到~p~n”,[Data]),
gen_tcp:发送(套接字、数据),
回路(插座);
{错误,已关闭}->
io:格式(“[S]闭合~n”,[]);
E->
io:格式(“[S]错误~p~n”,[E])
结束。
改进2
在关闭套接字之前,在客户端等待echo服务器发回数据
spawn(乐趣()->
{ok,Socket}=gen_tcp:connect(“127.0.0.1”,1111,[binary,{packet,0},{active,false}]),
{ok,Peername}=inet:Peername(套接字),
io:格式(“[C]对等名称~p~n”,[peername]),
gen_tcp:发送(套接字,),
案例gen_tcp:recv(套接字,0)的
{好的,数据}->
io:格式(“[C]得到~p~n”,[Data]),
gen_tcp:关闭(插座);
{错误,已关闭}->
io:格式(“[C]闭合~n”,[]);
E->
io:格式(“[C]错误~p~n”,[E])
结束
(完)。
例子
服务器应如下所示:
1>c(echo)。
{好的,回声}
2> 回声:听(1111)。
[S] peername{{127,0,0,1},57586}
[S] 得到
[S] 封闭的
客户机应该是这样的:
1>%粘贴来自改进2的代码
[C] peername{{127,0,0,1},1111}
[C] 得到
建议
正如@zxq9所提到的,这不是OTP风格的代码,可能不应该用于教育目的以外的任何用途
更好的方法可能是在服务器端侦听和接受连接时使用类似或的内容。这两个项目都有echo服务器的示例:和。您的套接字从不侦听,因此您不会收到消息。您还可以在发生任何事情之前立即从客户端关闭连接。控件也不会传递给套接字上的新进程。这里有一种不同的方法:在这种情况下,控制权最终被移交给了这个:注意,这不是OTP风格的代码,只是原始的Erlang。感谢您的帮助。我有一个问题,在客户端关闭套接字10秒后循环睡眠,为什么peername仍然第一次工作?我认为这取决于
inet\u描述符->state
标志以及inet\u描述符->peer\u ptr
存储的套接字地址(请参阅)。如果缓冲区中有数据,即使客户端已经关闭了连接,套接字看起来仍然被认为是活动的。一旦数据被读取,套接字很快就会被标记为非活动和关闭。谢谢,我会看一看。