Erlang动态接受传入的tcp连接

时间:2011-03-26 23:10:16

标签: tcp erlang gen-event

我想要解决的问题:拥有一个侦听特定端口的Erlang TCP服务器(代码应驻留在某种面向外部的接口/ API中),每个传入连接应由gen_server处理(即使gen_tcp:accept应该在gen_server内编码,但我实际上并不想最初产生预定义数量的接受传入连接的进程)。这有可能吗?

4 个答案:

答案 0 :(得分:10)

基本程序

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

  1. 使用gen_tcp:accept/1
  2. 收听传入的连接
  3. 每次返回连接时,告诉主管产生一个工作进程(例如另一个gen_server进程)
  4. 获取此流程的pid
  5. 使用新返回的套接字和该pid
  6. 调用gen_tcp:controlling_process/2
  7. 将套接字发送到该流程
  8.   

    注意: 必须按此顺序执行此操作,否则新进程可能会在所有权移交之前使用套接字。如果不这样做,旧进程可能会在新进程已经接管时获得与套接字相关的消息,从而导致数据包丢失或处理不当。

    监听过程应该只有一个责任,即产生新连接的工人。调用gen_tcp:accept/1时此过程将被阻止,这很好,因为已启动的工作人员将同时处理正在进行的连接。阻止接受可确保启动新连接时的最快响应时间。如果进程需要在中间执行其他操作,gen_tcp:accept/2可以与超时之间交错的其他操作一起使用。

    缩放

    • 您可以在单个侦听套接字上使用gen_tcp:accept/1等待多个进程,从而进一步提高并发性并最大限度地减少接受延迟。

    • 另一个优化方法是预先启动一些套接字工作程序,以便在接受新套接字后进一步减少延迟。

    • 第三个也是最后一个,是通过使用proc_libmore info)在您自己的自定义流程中实现OTP设计原则,使您的流程更轻量级。但是,如果您进行基准测试并得出结论认为gen_server行为会降低您的速度,那么您应该这样做。

答案 1 :(得分:4)

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

答案 2 :(得分:3)

您可能想要查看http://github.com/oscarh/gen_tcpd并使用handle_connection函数将您获得的进程转换为gen_server。

答案 3 :(得分:2)

你应该使用史蒂夫所说的“prim_inet:async_accept(Listen_socket,-1)”。 现在,handle_info回调将接受传入连接 (假设您的接口也是gen_server),因为您使用了异步 接听电话。

在接受连接时,你可以产生另一个ger_server(我建议 gen_fsm)并通过调用将其作为“控制过程” “gen_tcp:controlling_process(CliSocket,spwned process的Pid)”。

此后,该进程将接收来自套接字的所有数据 而不是你的界面代码。就像一个新的控制过程 会产生另一个连接。