无意中发现erlang服务器挺多使用prim_inet:async_accept,而不是gen_tcp:accept。查询了下文档和源码,这两个接口的主要区别还是在于同步和异步。async_accept是异步的,而accept是同步的,会一直阻塞到有连接到来才会返回。这里就涉及了很多有意思的概念,tcp accept的过程、同步、异步、阻塞和非阻塞,这篇文章的目的就是简要的记录并理清这些概念。
gen_tcp:accept
Accepts an incoming connection request on a listen socket. Socket must be a socket returned from listen/2. Timeout specifies a timeout value in ms, defaults to infinity.
gen_tcp模块提供的accept接口是一个阻塞的方法,我们需要指定timeout时间或者默认timeout时间为infinity。
prim_inet:async_accept
prim_inet:async_accept是一个非阻塞的异步accept接口。虽然文档上并没有说明该接口,只是在内部调用中使用,但是在rabbitmq等很多服务器的accept实现中都用到了这个异步accept的接口。
accept与async_accept的实现
查看prim_inet模块关于tcp accept的实现,可以发现,其实gen_tcp:accept的实现是基于async_accept的,gen_tcp:accept会一直阻塞在receive中等待消息。而直接调用async_accept的话,进程会在accept socket后收到消息{inet_async,…}。
{inet_async, L, Ref, {ok, S}}, S就是socket了。
%% For TCP sockets only.
%%
accept(L) -> accept0(L, -1).