erlang 调用 gen_tcp:accept时是会阻塞的,包括后续的gen_tcp:recv也是,但是这个阻塞实际是在erlang这边 receive等待driver返回消息,并不是阻塞在driver上,driver是不能阻塞的,这个mryufeng老大也很早就跟我说过,当时没明白,现在终于理解了
看下erlang 这边是如何做的
accept0(L, Time) when is_port(L), is_integer(Time) ->
case async_accept(L, Time) of
{ok, Ref} ->
receive
{inet_async, L, Ref, {ok,S}} ->
accept_opts(L, S);
{inet_async, L, Ref, Error} ->
Error
end;
Error -> Error
end.
async_accept(L, Time) ->
case ctl_cmd(L,?TCP_REQ_ACCEPT, [enc_time(Time)]) of
{ok, [R1,R0]} -> {ok, ?u16(R1,R0)};
Error -> Error
end.
可以看到prim_inet调用 ctl_cmd实际是通过port_control调用driver,这个是会立即返回的,但只是返回这个调用的成功/失败状态,而实际的accept后的结果是通过receive得到的,格式:
{inet_async, L, Ref, {ok,S}} S就是conn fd对应的port
那么driver里是怎么处理的呢,其实想让accept不阻塞肯定是使用的nonblocking + event notify 机制,也就是select/epoll之类的,看下
tcp_inet_ctl函数里的TCP_REQ_ACCEPT分支
if (desc->inet.state == TCP_STATE_ACCEPTING) {
//这个还没弄明白
} else if (desc->inet.state == TCP_STATE_MULTI_ACCEPTING) {
...
}else{
...
}
进入这个分支首先是对当前连接状态的一个判断,accept之前的状态是LISTEN,所以肯定执行的是else部分代码
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &n);
if (s == INVALID_SOCKET) {
if (sock_errno() == ERRNO_BLOCK) {
ErlDrvMonitor monitor;
if (driver_monitor_process(desc->inet.port, driver_caller(desc->inet.port),
&monitor) != 0) {
return ctl_xerror("noproc", rbuf, rsize);
}
enq_async_w_tmo(INETP(desc), tbuf, TCP_REQ_ACCEPT, timeout, &monitor);
desc->inet.state = TCP_STATE_ACCEPTING;
sock_select(INETP(desc),FD_ACCEPT,1);
if (timeout != INET_INFINITY) {
driver_set_timer(desc->inet.port, timeout);
}
} else {
return ctl_error(sock_errno(), rbuf, rsize);
}
} else {
}
这段代码首先调用了sock_accept,这个封装的宏也是为了跨平台的通用,其实linux上就是accept,由于之前创建socket时已经设置描述字为非阻塞了,所以这个会立即返回-1,就是INVALID_SOCKET,并且errno全局变量的值是11,EWOULDBLOCK,sock_errno也是为了通用
后面的driver_monitor_process是监控调用者erlang进程,然后enq_async_w_tmo实际是保存当前异步请求到一个队列中,核心的是调用sock_select这个函数,并且根据timeout设置了定时器,看下sock_select实现,实际最终调用的是erl_driver.h中定义的
int driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on)
实际就是注册当前关心的事件 socket/pipe 读写等事件,由emulator通过 epoll/select 进行event notify,回调的是driver里定义的ready_input/ready_output函数,这里对应的就是
static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
这个函数无非就是调用accept,然后返回连接描述字,最终通过tcp_inet_copy里的
/* The new port will be linked and connected to the original caller */
port = driver_create_port(port, owner, "tcp_inet", (ErlDrvData) copy_desc);
创建了一个新的port返回给erlang端调用,处理后续连接描述字的读写事件
看完这些能对gen_tcp driver异步工作的机制有个大概了解,细节实现还有非常多的地方需要研究,erl_driver.h的实现回头也需要一起看一下
分享到:
相关推荐
cmsdk_ahb_to_apb_async.v
本示例“TCP_ASYNC_SERVER.rar”关注的是异步TCP服务器的实现,这是一种利用Winsock库在Windows平台上构建的高效通信模型。异步TCP服务器不同于同步服务器,因为它能够在处理一个连接的同时接收新的连接请求,从而...
在C#中,可以通过事件驱动的异步模式(如`BeginConnect`/`EndConnect`,`BeginReceive`/`EndReceive`)或者使用`async`/`await`关键字配合`Task`来实现异步操作。 在这个项目中,`TCP.rar`可能包含了以下部分: 1....
6. **多线程或async/await**:在服务器端,为了处理多个并发连接,通常会使用多线程或者C#的async/await关键字配合Task类实现异步处理,这样可以在不阻塞主线程的情况下处理多个客户端请求。 通过这个示例项目,...
标题中的“MODBUS TCP.rar_C#MODBUS TCP_modbus TCP_modbus-tcp c_modbus_tcp_t”表明这个压缩包文件包含的是关于C#语言实现MODBUS TCP通信的相关资源。MODBUS TCP是一种基于MODBUS协议的网络通信协议,常用于工业...
在Python编程语言中,"Python_gen_async" 涉及的核心概念是生成器(Generators)和异步编程。这两个特性极大地提升了Python处理大量数据和并发任务的能力。 生成器(Generators)是Python中一种特殊的迭代器,允许...
MODBUS TCP Client_c#modbus_tcp_modbusTCP_源码是一个关于使用C#编程语言实现MODBUS TCP协议的客户端程序的示例项目。MODBUS是一种广泛应用于工业自动化领域的通信协议,它允许设备之间进行简单的数据交换。在C#...
此外,C#中的异步编程模型(async/await)也能用于TCP客户端,以实现非阻塞的IO操作,提高程序的响应性。例如,可以将Connect、Read和Write方法改写为异步版本: ```csharp async Task ConnectAsync() { await ...
而在OCaml语言中,尽管有着自己的并发库如Async,但直接移植或模仿Erlang的gen_server概念可以为OCaml开发者带来更丰富的工具选择。本文将深入探讨如何在OCaml/Async环境下实现类似gen_server的功能,并对这一过程...
在VB(Visual Basic)编程环境中,`vb_socket_tcp`是一个涉及网络通信的重要概念,它主要基于TCP(Transmission Control Protocol)协议来实现客户端和服务器之间的数据交换。TCP是一种面向连接的、可靠的传输层协议...
4. **并发处理**:如何在TCP和UDP中处理多个并发连接,包括线程池、异步编程模型(如C#的async/await)和事件驱动编程。 5. **网络安全性**:涉及TCP和UDP在网络安全方面的考量,如SSL/TLS加密通信。 6. **性能...
TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在C#中实现TCP通信,开发者可以使用.NET框架提供的System.Net.Sockets命名空间中的TcpClient和...
在IT领域,网络通信是不可或缺的一部分,而TCP(Transmission Control Protocol)作为一种面向连接的、可靠的传输层协议,广泛用于各种应用程序。本资料“tcp.rar”包含了一段C#语言实现的端口监听代码,以及可能...
在实际应用中,为了提高效率和用户体验,可以考虑使用异步编程模型,例如使用BeginAcceptTcpClient/EndAcceptTcpClient和BeginSend/EndReceive等异步方法,或者使用async/await语法。同时,考虑到文件大小和网络状况...
《异步FIFO在Verilog中的实现——深入解析async_fifo.v》 在数字系统设计中,FIFO(First-In-First-Out,先进先出)存储器是一种常用的缓冲数据结构,它能够有效地解决数据传输速率不匹配的问题。在Verilog硬件描述...
《深入理解Async FIFO:原理与应用》 在计算机系统中,FIFO(First In First Out,先进先出)是一种常见的数据结构,广泛应用于缓存、队列和数据传输等领域。而Async FIFO,即异步FIFO,是FIFO的一种特殊形式,它在...
《Python库meilisearch_python_async-0.14.0-py3-none-any.whl详解》 在Python的世界里,库是开发者的重要工具,它们提供了丰富的功能,简化了编程工作。本文将深入探讨名为“meilisearch_python_async”的Python库...
9. **网络编程概念**:理解IP地址、端口号、套接字(Socket)等网络编程基本概念,以及TCP/UDP通信的工作流程。 10. **异步编程**:VB提供了异步编程模型,如Async/Await关键字,使得在处理网络通信时可以避免阻塞...
在"Async_fifo_vhdl"标签中,我们可以推测这个压缩包可能包含了一个用VHDL编写的异步FIFO实现。VHDL是一种硬件描述语言,它允许设计者用代码来描述数字系统的逻辑行为,然后可以被综合工具转换为具体的电路布局。一...
异步和同步的栅栏函数都有以下特点: 1、通过dispatch_barrier_(a)sync添加的block会等待前边所有...ispatch_barrier_async将自己的任务插入到queue之后,不会等待自己的任务结束,它会继续把后面的任务插入到queue。