我对“Erlang和OTP在行动中”的第4章示例感到困惑。 https://github.com/erlware/Erlang-and-OTP-in-Action-Source/blob/master/chapter_04/tcp_rpc/src/tr_server.erl#L92
handle_info(timeout, #state{lsock = LSock} = State) ->
{ok, _Sock} = gen_tcp:accept(LSock),
{noreply, State}.
这本书说:
您不需要记住accept返回的套接字句柄, 因为它也包含在每个数据包中。
这究竟是什么意思?什么是“数据包”? 为什么套接字句柄名称以下划线为前缀?为什么不需要在GC的情况下保存它?场景背后会发生什么?
gen_server行为似乎很难遵循。有人可以用简单明了的方式解释它吗?
答案 0 :(得分:2)
使用tcp套接字在erlang中建立连接时,可以使套接字处于活动状态或不活动状态。
如果套接字处于活动状态,则每次从客户端收到一些数据时,它都会以格式为{tcp, Socket, Data}
的Erlang消息发送,tcp
只是元组ID,{{1} }是一个变量,其中包含有关Socket的所有信息,例如您正在侦听的本地端口,在哪个接口上,以及发送数据的对等端口的端口/ IP,Socket
是发送的数据。 / p>
这就是你不需要记住Socket的原因,因为每次收到一个包时,你都会以Data
作为参数。
如果将套接字设置为非活动状态,则需要使用函数Socket
才能接收任何数据。活动套接字更容易使用,但是如果你有太多的流量,它可能会使Erlang消息系统过载,所以当你期望高负载时,你总是使用非活动套接字。
“数据包”基本上是通过连接发送的包,在这个例子中,客户端发送的命令只是在一个数据包中发送,因为它是一个小包,但想象一下客户端必须的数据发送给你,而不是10或20个字符,就像100kb,你不会在一个单独的包中得到它,你将获得不同包中的数据,以及你作为程序员的责任,把你得到的所有数据多个数据包都在一起。
在Erlang中,当您进行模式匹配时,您可以使用下划线匹配任何内容,例如
recv/2
无论您对变量Anything有什么约束,该模式匹配始终为true。现在,想象一下你的代码中都有下划线,有时候你会想要添加更好的代码文档而感到困惑,所以你在下划线之后添加一些内容,比如
{expected, _} = {expected, Anything}
所以现在你不关心中间名,因为你根本不需要它,但是你在代码中记录了元组的第二个值应该具有中间名的内容。
垃圾收集器不会收集正在使用的套接字。
{expected, _MiddleName} = {expected, Anything}
只是一个用Erlang编写的通用服务器,它实际上是一个很大的主题,因为它是OTP架构的一部分,你可以在这个link上找到一个好的主题,但是很少说,你开始做erlang,你意识到你编写了相同的代码来初始化服务器(我不是在这里谈论tcp服务器,而是关于Erlang服务器,这是一个监听Erlang消息的过程,当接收任何它的行为和回答与否,它将回答同步消息,并且不会回答异步消息)。正如我所说,随着时间的推移,你会意识到你一遍又一遍地写相同的初始化,相同的初始化函数等等。
otp_server只是一个Erlang模块,它抽象出你使用的一遍又一遍重复的相同代码,并且让你只关注任务来编写执行某些自定义函数的真实代码以便为其客户服务,并且因为它被每个人使用,它提供了一个固定的结构,每个erlang程序员都能理解,并且每个程序员都可以在没有重大问题的情况下遵循。在我给你的链接上,它显示了编写一个没有otp的Erlang服务器模块的完美示例,为所有下一个服务器模块编写通用服务器模块模板,它最终解释了它正是OTP为你做的。