为何Node.js Net库中server.close()早于server.on('connection')执行?
问题:Node.js Net库中server.close()执行时机早于connection事件的原因
我正在学习Node.js的Net库,遇到一个疑问:为何在如下示例中,server.close()的执行时机早于server.on('connection')?我知道如何让代码正常运行,但无法理解为何客户端套接字在服务器关闭后才尝试连接,而非关闭前。
代码示例
let server = require('./server') // let server = new net.Server().listen(2000) let client = require('./client') // let client = new net.Socket() let client2 = require('./client2') // let client2 = new net.Socket() server.on('listening', () => console.log('Server listening')) client.on('connect', () => console.log('Client connected')) client2.on('connect', () => console.log('Client2 connected')) client.connect(2000) client2.connect(2000) server.on('error', (err) => console.log('Server error: ' + err)) client.on('error', (err) => console.log('Client error: ' + err)) client2.on('error', (err) => console.log('Client2 error: ' + err)) server.close(() => console.log('Server closed'))
运行输出
未注释server.close()时
Server closed Client2 error: Error: connect ECONNREFUSED ::1:2000 Client error: Error: connect ECONNREFUSED ::1:2000
注释server.close()时
Server listening Client connected Client2 connected
原因分析
问题的核心是Node.js的异步事件循环机制,再加上server.listen()和server.close()的执行特性:
server.listen()是异步操作:调用listen(2000)不会立刻让服务器开始监听端口,它只是给操作系统发了个“帮我监听2000端口”的请求,这个请求完成(也就是触发listening事件)要等到事件循环的后续阶段才会执行,并非同步完成。- 代码是同步执行的:你的代码从上到下按顺序同步运行,在调用完客户端的
connect()之后,马上就调用了server.close()。这时候服务器连监听端口的操作都还没完成,listening事件都没触发——因为异步的listen操作还没轮到执行。 server.close()的执行逻辑:如果服务器还没真正开始监听端口,调用server.close()会直接终止正在初始化的监听请求,而且关闭流程会很快走完(毕竟此时既没有活跃连接,也没在监听端口),所以Server closed会先被打印出来。- 客户端连接也是异步的:
client.connect()同样是异步操作,它的连接请求要等到事件循环的后续阶段才会真正发出去。这时候服务器已经关闭,2000端口没人监听,自然就会返回连接被拒绝的错误。
修正示例
如果要让服务器先监听、接受客户端连接后再关闭,需要把server.close()放到异步事件的回调中,比如listening事件或者客户端的connect事件里:
server.on('listening', () => { console.log('Server listening') // 延迟关闭,确保客户端连接完成 setTimeout(() => { server.close(() => console.log('Server closed')) }, 100) })
这样就能得到预期的执行顺序:先触发listening和客户端的connect,再执行关闭操作。
内容的提问来源于stack exchange,提问作者Georgii Galechyan
相关产品推荐
相关产品推荐

