即使主线程被阻塞,节点也接受了新的套接字连接 #3473

Posted

技术标签:

【中文标题】即使主线程被阻塞,节点也接受了新的套接字连接 #3473【英文标题】:Node accepted new socket connection even when main thread is blocked #3473 【发布时间】:2021-09-25 10:13:17 【问题描述】:

Node.js 版本:v10.19.0 操作系统:Ubuntu 18 范围(安装、代码、运行时、元、其他?): 模块(和版本)(如果相关):http

const http =  require('http');

const server = http.createServer((req,res)=>
    console.log('a new http request');    
    let d = Date.now();

    while(Date.now()-d <  50000) 
    // block for 50 seconds here
    
);

server.on('connection',function()
    console.log('new connection');
);
server.listen(3500); 

所以我在请求处理程序中从 3500 开始有一个 http 服务器,我在每个请求上阻塞 50 秒,现在从终端我一个接一个地点击 3 curl,我看到新连接被打印,然后是一个新的 http 请求,然后在 50 秒后我看到另一个新连接被打印等等,但是如果我运行命令 netstat -an -p tcp | grep 3500 ,在点击 3 back to back curl 后,我可以看到已经建立了 6 个套接字连接(每个 curl 有 2 个),我的问题是因为 node 使用单个线程并等待 epoll ,在它接受第一个连接并创建一个新的socket ,它阻塞了接下来的 50 秒,然后其他 2 个连接是如何建立的,下面是 netstat 运行三个背靠背 curl localhost:3500 后的结果

tcp 0 0 127.0.0.1:35998 127.0.0.1:3500 ESTABLISHED 4286/curl
tcp 0 0 127.0.0.1:36000 127.0.0.1:3500 ESTABLISHED 4292/curl
tcp 0 0 127.0.0.1:35996 127.0.0.1:3500 ESTABLISHED 4281/curl
tcp6 2 0 :::3500 :::* LISTEN 4238/node
tcp6 78 0 127.0.0.1:3500 127.0.0.1:35998 ESTABLISHED -
tcp6 0 0 127.0.0.1:3500 127.0.0.1:35996 ESTABLISHED 4238/node
tcp6 78 0 127.0.0.1:3500 127.0.0.1:36000 ESTABLISHED -

【问题讨论】:

【参考方案1】:

连接建立是在操作系统内核中完成的,无论应用程序是否忙于做事。然后,当应用程序调用accept 时,已建立的连接会传播到应用程序,这是由节点完成的。您可以看到该请求实际上还没有被应用程序处理,因为只有一个new connection,即第一次调用 curl 的那个。

【讨论】:

好的,但是节点事件循环使用epoll并阻塞,直到它接受侦听套接字上的连接,这会创建一个新套接字,但是在第一次curl之后已经创建了另外2个新套接字,然后谁接受传入的连接,我来自这个视频youtube.com/watch?v=P9csgxBgaZ8&t=665s,你是什么意思应用程序正在调用accept,你的意思是监听套接字接受连接并给它一个新的专用套接字,另一个问题是tcp握手已经为其他2个套接字完成第一次卷曲后 @TarunPrakashSingh: "... 那么谁接受了传入的连接," - 正如我所说,连接建立已经在操作系统内核中完成,在应用程序之外。拥有这个已建立的连接就足以让 curl 发送它的请求。 所以 tcp 握手已经在内核级别完成并且侦听套接字接受了连接并将新套接字专用于客户端,这一切都是在第一次 curl 请求后节点阻塞时发生的? @TarunPrakashSingh:是的,所有这些都是在没有涉及应用程序的情况下完成的。 再次 - 请区分操作系统内核中发生的事情和应用程序中发生的事情。该视频仅讨论应用程序方面。 TCP 握手在内核内部完成,应用程序在调用accept 时获取已经建立的套接字。如果您仍然不理解这一点,我将放弃解释,因为我无法给出与我之前多次给出的相同答案,但措辞略有不同。

以上是关于即使主线程被阻塞,节点也接受了新的套接字连接 #3473的主要内容,如果未能解决你的问题,请参考以下文章

TCP阻塞模型下服务器和客户端的建立步骤

如何中止winsock阻塞调用?

当主线程显然未阻塞时,QProgressDialog 冻结

11 非阻塞套接字与IO多路复用(进阶)

非阻塞套接字多线程接收模型

eventfd,添加写入套接字的值