为什么不需要记住handle_info中的套接字句柄?

Why no need to remember the socket handle in handle_info?

我对 "Erlang and OTP in action" 的第 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}.

书上说:

You don’t need to remember the socket handle returned by accept, because it’s also included in each data package.

具体是什么意思? "data package" 是什么? 为什么套接字句柄名称前加下划线?为什么不需要将它保存在某个地方以防 GC?幕后发生了什么?

gen_server 行为似乎很难理解。有人可以简单明了地解释一下吗?

当你在erlang中使用tcp套接字建立连接时,你可以使套接字处于活动状态或不活动状态。

如果套接字处于活动状态,每次您从客户端接收到一些数据时,它都会作为格式为 {tcp, Socket, Data} 的 Erlang 消息发送,tcp 只是元组 ID,Socket 是一个变量,其中包含有关 Socket 的所有信息,例如正在侦听的本地端口、接口以及发送数据的对等方的 port/ip,而 Data 是数据已发送。

这就是您不需要记住 Socket 的原因,因为每次收到包裹时,您都会将 Socket 作为消息的参数。

如果您将套接字设置为非活动状态,则需要使用函数recv/2 才能接收任何数据。活动套接字更易于使用,但如果流量过多,它会使 Erlang 消息传递系统过载,因此当您期望高负载时,请始终使用非活动套接字。

A "data package" 基本上是通过连接发送的数据包,在这个例子中,客户端发送的命令只是在一个数据包中发送,因为它是一个小数据包,但想象一下数据客户必须向您发送,而不是 10 或 20 个字符,就像 100kb,您不会将它放在一个包中,您将在不同的包中获取数据,作为程序员,您有责任放置所有数据您同时获得多个数据包。

在 Erlang 中,当您进行模式匹配时,您可以匹配任何带有下划线的内容,例如

{expected, _} = {expected, Anything}

无论您在变量 Anything 上绑定了什么,模式匹配始终为真。现在,假设你的代码中到处都是下划线,有时它会让人感到困惑,你想添加更好的代码文档,所以你在下划线后面添加一些东西,比如

{expected, _MiddleName} = {expected, Anything}

所以现在您不关心中间名,因为您根本不需要它,但是您在代码中记录了元组的第二个值应该具有中间名的内容。

垃圾收集器不会收集正在使用的套接字。

gen_server 只是一个用 Erlang 编写的通用服务器,它实际上是一个很大的话题,因为它是 OTP 体系结构的一部分,你可以找到关于这个 link 的很好的教程,但只言片语,当你开始做 erlang 时,你会意识到你编写了相同的代码来初始化服务器(我在这里不是在谈论 tcp 服务器,而是在谈论 Erlang 服务器,这是一个侦听 Erlang 消息以及何时接收任何消息的进程行为和回答,或不回答,它会回答同步消息,不会回答异步消息)。所以正如我所说,随着时间的推移,你会意识到你一遍又一遍地编写相同的初始化、相同的初始化函数等。

otp_server 只是一个 Erlang 模块,它抽象出你使用的相同代码,一遍又一遍地重复,让你只专注于编写真正的代码来执行一些自定义功能的任务为了服务于它的客户,并且因为它被每个人使用,它提供了一个固定的结构,每个 erlang 程序员都理解并且每个程序员都可以遵循而不会出现重大问题。在我给你的 link 上,它展示了一个完美的例子,在没有 otp 的情况下编写一个 Erlang 服务器模块,为你所有的下一个服务器模块编写一个通用的服务器模块模板,最后解释了 OTP 的作用你.