Erlang动态接受传入的TCP连接

10
我要解决的问题:拥有一个 Erlang TCP 服务器,监听特定端口(代码应位于某种外部接口/API中),每个传入连接都应由 gen_server 处理(即 gen_tcp:accept 应编写在 gen_server 内部),但我实际上不想最初生成预定义数量的进程来接受传入连接。这是否可能?
4个回答

11

基本过程

您应该有一个静态进程(实现为一个 gen_server 或自定义进程),执行以下过程:

  1. 使用 gen_tcp:accept/1 监听传入连接
  2. 每次返回一个连接时,告诉监督者生成一个工作进程(例如另一个 gen_server 进程)
  3. 获取该进程的 pid
  4. 使用新返回的 socket 和该 pid 调用gen_tcp:controlling_process/2
  5. 将 socket 发送到该进程

注意: 必须按照以上顺序执行,否则新进程可能在所有权移交之前使用该 socket。如果不这样做,则当新进程已经接管时,旧进程可能会收到与 socket 相关的消息,导致数据包丢失或处理不当。

监听进程应该只有一个职责,即为新连接生成工作进程。此进程在调用 gen_tcp:accept/1 时将被阻塞,这是可以接受的,因为已启动的工作进程将同时处理进行中的连接。阻塞在 accept 上可以确保在初始化新连接时获得最快的响应时间。如果进程需要在其中执行其他操作,可以使用 gen_tcp:accept/2 并在超时之间交替执行其他操作。

扩展

  • 您可以在单个侦听 socket 上使用多个使用 gen_tcp:accept/1 等待的进程,进一步提高并发性并最小化 accept 的延迟。

  • 另一个优化是预先启动一些 socket 工作进程以进一步减少接受新套接字之后的延迟。

  • 第三点,可以通过使用 proc_lib 实现 OTP 设计原则来使您的进程更加轻量级 (了解更多)。但是,只有在基准测试并得出结论是 gen_server 行为影响性能时,才应该采用这种方式。


  • 谢谢,我会尝试这个方法,因为它似乎是最可行的。 - hyperboreean

    4
    < p > gen_tcp:accept 的问题在于它会阻塞,因此如果你在 gen_server 中调用它,你就会阻塞服务器无法接收其他消息。你可以尝试通过传递超时时间来避免这种情况,但这最终会变成一种轮询形式,最好避免使用。相反,你可以尝试使用 Kevin Smith's gen_nb_server;它使用了一个内部未记录的函数 prim_inet:async_accept 和其他 prim_inet 函数来避免阻塞。


    但是,如果我能找到一种将 gen_tcp:accept 转发到自己的 gen_server 的方法,那么我就不会在意它是否阻塞。但我猜想无法事先知道(比如从 gen_tcp:listen)是否有一个需要接受的传入连接。感谢指向 gen_nb_server!你在生产中使用过它吗? - hyperboreean
    我认为你不需要使用gen_nb_server来完成你的任务。你的情况非常简单。 - Adam Lindberg
    1
    我从未在生产中使用过 gen_nb_server,但已经在生产中使用了 prim_inet:async_accept - Steve Vinoski
    1
    我推荐使用 gen_nb_server,因为原问题中要求使用 gen_server。我同意使用 proc_lib 进程可能更好、更容易;这正是我们在 Yaws 中生成接收器的方式。 - Steve Vinoski

    3

    2
    您应该使用"prim_inet:async_accept(Listen_socket, -1)",如Steve所说。 现在,您的handle_info回调将接受传入的连接(假设您的接口也是gen_server),因为您已经使用了异步接受调用。
    在接受连接后,您可以生成另一个ger_server(我建议使用gen_fsm),并通过调用“gen_tcp:controlling_process(CliSocket,生成进程的Pid)”将其作为“控制进程”。
    此后,所有来自套接字的数据都将由该进程接收,而不是由您的接口代码接收。这样就会为另一个连接生成一个新的控制进程。

    请勿抄袭他人内容。 - Peer Stritzinger
    是的,我已经从我的 Erlang 应用程序中剪切并粘贴了它。那么我需要征得自己的许可吗? - Arunmu
    1
    抱歉,初看起来像是一封邮件列表对话的片段。 - Peer Stritzinger
    没关系,Peer。你在 Stack Overflow 上已经回答了我关于同一个应用程序的问题。 :) - Arunmu
    我在gen_server中调用了"prim_inet:async_accept()"来异步监听新连接,但不确定使用多少此类进程是合理的。我的使用场景是需要处理大量并发连接请求。 - null

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接