如何使用同一个套接字发出两个请求?

How to make two requests using the same socket?

提问人:stackhatter 提问时间:5/22/2023 最后编辑:stackhatter 更新时间:9/3/2023 访问量:55

问:

此代码发出两个请求。但是,它们使用不同的套接字。如何配置 or 请求以使两个请求使用相同的套接字?ServerAgent

import { Server, IncomingMessage, ServerResponse, Agent, request } from 'node:http';
import { Socket } from 'node:net';

console.log('\n\n');

let server = new Server({ keepAlive: true});
server.addListener('request', (req: IncomingMessage, res: ServerResponse) => {

    console.log('Server_request');
    console.log(req.headers);
    console.log('IncomingMessage.socket.remotePort', req.socket.remotePort);

    let data = '';

    req.addListener('data', (chunk: string) => {
        console.log('IncomingMessage_data');
        data = data + chunk;
    })

    req.addListener('close', () => {
        console.log('IncomingMessage_close');
    });

    req.addListener('end', () => {
        console.log('IncomingMessage_end');
        res.end('');
    });
})

server.listen(3000, "127.0.0.1");

server.addListener('close', () => console.log('sever_close'));

server.addListener('connection', (socket: Socket) => {
    // "This event is emitted when a new TCP stream is established (https://nodejs.org/api/http.html#event-connection)." 
    socket.addListener('close', () => console.log('Socket_close'));
    console.log("Socket.localPort", socket.localPort);
    console.log("Socket.remotePort", socket.remotePort);
})

let agent = new Agent({ keepAlive: true, maxSockets: 1});

let req0 = request(
    { 
        agent: agent,
        hostname: '127.0.0.1',
        port: 3000,
        path: '/',
        method: 'POST'
    }, (res:IncomingMessage)=>{
        console.log(res.headers);
    });

req0.end("0");

let req1 = request(
    {
        agent: agent,
        hostname: '127.0.0.1',
        port: 3000,
        path: '/',
        method: 'POST'
    }, (res:IncomingMessage)=>{ 
        console.log(res.headers);
    });

req1.end("1");

这是一个可能的结果:

Socket.localPort 3000
Socket.remotePort 38880
Server_request
{
  host: '127.0.0.1:3000',
  connection: 'keep-alive',
  'content-length': '1'
}
IncomingMessage.socket.remotePort 38880
IncomingMessage_data
IncomingMessage_end
IncomingMessage_close
{
  date: 'Sun, 21 May 2023 18:53:56 GMT',
  connection: 'keep-alive',
  'keep-alive': 'timeout=5',
  'content-length': '0'
}
Socket_close
Socket.localPort 3000
Socket.remotePort 34564
Server_request
{
  host: '127.0.0.1:3000',
  connection: 'keep-alive',
  'content-length': '1'
}
IncomingMessage.socket.remotePort 34564
IncomingMessage_data
IncomingMessage_end
IncomingMessage_close
{
  date: 'Sun, 21 May 2023 18:54:01 GMT',
  connection: 'keep-alive',
  'keep-alive': 'timeout=5',
  'content-length': '0'
}
Socket_close
节点 .js 类型脚本 TCP 保持活动状态

评论

0赞 500 - Internal Server Error 5/22/2023
为什么,有什么意义?
0赞 stackhatter 5/22/2023
@500-InternalServerError请让我知道为什么它毫无意义。谢谢。
0赞 freakish 5/22/2023
@stackhatter不,不。你试图在没有充分理由的情况下做某事。这足以成为不这样做的理由。套接字是一种低级网络结构,直接处理它们很少是一个好主意。尤其是当您有一个为您处理所有令人讨厌的细节的库时。这看起来像 XY 问题。所以问题是:你到底想实现什么?你为什么还要在乎?
0赞 stackhatter 5/22/2023
@freakish 我不认为这是 XY 问题,因为我发布的问题正是我试图解决的问题。我解决了 - 我发布了解决方案。
0赞 user207421 5/22/2023
@500-InternalServerError HTTP确实开箱即用。

答:

1赞 stackhatter 5/22/2023 #1

这里的“诀窍”是耗尽响应;这允许后续请求在关闭之前使用相同的套接字继续进行(即 res.resume();):

import { Server, IncomingMessage, ServerResponse, Agent, request } from 'node:http';
import { Socket } from 'node:net';

console.log('\n\n');

let server = new Server({ keepAlive: true, keepAliveTimeout: 4000 });

server.addListener('request', (req: IncomingMessage, res: ServerResponse) => {

    console.log('Server_request');
    console.log(req.headers);
    console.log('IncomingMessage.socket.remotePort', req.socket.remotePort);

    let data = '';

    req.addListener('data', (chunk: string) => {
        console.log('IncomingMessage_data');
        data = data + chunk;
    });

    req.addListener('close', () => {
        console.log('IncomingMessage_close');
    });

    req.addListener('end', () => {
        console.log('IncomingMessage_end');
        res.end('');
    });
});

server.listen(3000, "127.0.0.1");

server.addListener('close', () => console.log('Server_close'));

server.addListener('connection', (socket: Socket) => {
    // "This event is emitted when a new TCP stream is established (https://nodejs.org/api/http.html#event-connection)." 
    socket.addListener('close', () => console.log('Socket_close'));
    console.log("Socket.localPort", socket.localPort);
    console.log("Socket.remotePort", socket.remotePort);
})

let agent = new Agent({ keepAlive: true, maxSockets: 1, timeout: 2000 });

// The agent will keep the socket open for 2 seconds.
let req0 = request(
    {
        agent: agent,
        hostname: '127.0.0.1',
        port: 3000,
        path: '/',
        method: 'POST'
    }, (res: IncomingMessage) => {
        console.log(res.headers);
        res.resume();
    });

req0.end("0");

// The Socket is still open; hence, make another request using the same destination port number (i.e., the same socket).
let req1 = request(
    {
        agent: agent,
        hostname: '127.0.0.1',
        port: 3000,
        path: '/',
        method: 'POST'
    }, (res: IncomingMessage) => {
        console.log(res.headers);
        res.resume();
        // Drain the Readable.
    });

req1.end("1");


setTimeout(() => {
    // Use the same agent to make another request.
    // The Socket has been closed (> 2000ms); hence, this request will likely have a different destination port number (i.e., a new Socket).
    let req2 = request(
        {
            agent: agent,
            hostname: '127.0.0.1',
            port: 3000,
            path: '/',
            method: 'POST'
        }, (res: IncomingMessage) => {
            console.log(res.headers);
            res.resume();
            // Drain the Readable.
        });

    req2.end("2");
}, 5000);