我想要解决的问题:拥有一个侦听特定端口的Erlang TCP服务器(代码应驻留在某种面向外部的接口/ API中),每个传入连接应由gen_server
处理(即使gen_tcp:accept
应该在gen_server
内编码,但我实际上并不想最初产生预定义数量的接受传入连接的进程)。这有可能吗?
答案 0 :(得分:10)
您应该有一个静态进程(实现为gen_server
或自定义进程),执行以下过程:
gen_tcp:accept/1
gen_server
进程)gen_tcp:controlling_process/2
注意: 您必须按此顺序执行此操作,否则新进程可能会在所有权移交之前使用套接字。如果不这样做,旧进程可能会在新进程已经接管时获得与套接字相关的消息,从而导致数据包丢失或处理不当。
监听过程应该只有一个责任,即产生新连接的工人。调用gen_tcp:accept/1
时此过程将被阻止,这很好,因为已启动的工作人员将同时处理正在进行的连接。阻止接受可确保启动新连接时的最快响应时间。如果进程需要在中间执行其他操作,gen_tcp:accept/2
可以与超时之间交错的其他操作一起使用。
您可以在单个侦听套接字上使用gen_tcp:accept/1
等待多个进程,从而进一步提高并发性并最大限度地减少接受延迟。
另一个优化方法是预先启动一些套接字工作程序,以便在接受新套接字后进一步减少延迟。
第三个也是最后一个,是通过使用proc_lib
(more 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)”。
此后,该进程将接收来自套接字的所有数据 而不是你的界面代码。就像一个新的控制过程 会产生另一个连接。