关闭TCP套接字有4个步骤。
客户端关闭FIN_WAIT_1 FIN M =>服务器
客户端FIN_WAIT_2 <= ACK M +1个服务器CLOSE_WAIT
客户端TIME_WAIT <= FIN N服务器LAST_ACK
客户端ACK N +1 =>服务器已关闭
如果客户端进程在服务器发送响应之前被杀死,那么客户端是否由于已死而不能发送最后一个ACK?服务器不释放“ CLOSE_WAIT”吗?
server.js
// npm i sleep
const http = require('http');
const sleep = require('sleep').sleep;
const server = http.createServer(async (req, res) => {
res.statusCode = 200;
console.log('get a request');
await sleep(30); // sleep 30s
res.end('goodbye\n');
console.log('finish a request');
});
server.listen(6000);
client.js
const http = require('http');
const net = require('net');
const options = {
port: 6000,
host: '127.0.0.1',
method: 'GET'
// path: ''
};
const req = http.request(options, res => {
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log('Response: ' + chunk);
});
});
req.on('error', e => {
console.error(`request error: ${e.message}`);
});
req.end();
setTimeout(() => {
process.exit(1);
}, 2000);
~ netstat -tanv | grep 6000
tcp4 0 0 127.0.0.1.6000 127.0.0.1.57786 CLOSE_WAIT 408241 146988 40426 0 0x0122 0x00000104
tcp4 0 0 127.0.0.1.57786 127.0.0.1.6000 FIN_WAIT_2 408300 146988 40434 0 0x2131 0x00000100
我希望“ CLOSE_WAIT”在服务器上持续存在,因为它没有从客户端获得ACK,但是30秒钟后它将清除。
答案 0 :(得分:1)
以下是RedHat对CLOSE_WAIT的描述:
CLOSE_WAIT-表示服务器已收到第一个FIN信号 来自客户端,并且连接正在关闭中。这表示 套接字正在等待应用程序执行close()。插座可以在 CLOSE_WAIT状态无限期,直到应用程序将其关闭。错误场景 就像文件描述符泄漏:服务器未在套接字上执行close() 导致堆积CLOSE_WAIT套接字。
这纯粹是服务器端的问题,无论客户端是否被杀死。 30秒后超时的原因是因为套接字在睡眠30秒时一直处于打开状态,因此允许发送响应(当然为时已晚)并关闭套接字。
这与Java vs节点无关,只是处理请求的设计决定。