套接字解析查找后立即触发回调

Posted

技术标签:

【中文标题】套接字解析查找后立即触发回调【英文标题】:Trigger callback as soon as socket has resolved lookup 【发布时间】:2021-11-09 19:10:34 【问题描述】:

我正在尝试运行一些代码,这些代码为 http 请求生命周期中的各个阶段(套接字、dns 查找、连接或安全连接、ttfb、结束)创建跟踪跨度。到目前为止,它看起来或多或少是这样的:

function tracedRequest(
    options: HttpRequestOptions | HttpsRequestOptions,
    callback: ResponseCallback
): ClientRequest 
    const isHttps = options.protocol === 'https' || options.agent instanceof HttpsAgent;
    const transport = isHttps ? https.request : http.request;

    const requestSpan = tracer.createChildSpan( name: 'request' );

    if (!tracer.isRealSpan(requestSpan)) 
        return transport.call(null, options, callback);
    

    let socketSpan: ISpan | undefined;
    let dnsSpan: ISpan | undefined;
    let tcpSpan: ISpan | undefined;
    let tlsSpan: ISpan | undefined;
    let ttfbSpan: ISpan | undefined;

    const onLookup = () => 
        dnsSpan?.endSpan();
        tcpSpan = tracer.createChildSpan( name: 'http_tcp_handshake' );
    ;

    const onConnect = () => 
        tcpSpan?.endSpan();
        if (isHttps) 
            tlsSpan = tracer.createChildSpan( name: 'http_tls_handshake' );
         else 
            ttfbSpan = tracer.createChildSpan( name: 'http_ttfb' );
        
    

    const onSecureConnect = () => 
        tlsSpan?.endSpan();

        // just in case secureConnect is emmited not only for https transports
        if (isHttps) 
            ttfbSpan = tracer.createChildSpan( name: 'http_ttfb' );
        
    

    const onResponse = (response: IncomingMessage) => 
        ttfbSpan?.endSpan();

        response.prependOnceListener('end', () => 
            requestSpan.endSpan();
        );
    

    const onSocket = (socket: Socket | TLSSocket) => 
        socketSpan.endSpan();
        socket.prependOnceListener('lookup', onLookup);

        deferToConnect(socket, 
            connect: onConnect,
            secureConnect: onSecureConnect
        );
    

    socketSpan = tracer.createChildSpan( name: 'http_establish_socket' );
    const request: ClientRequest = transport.call(null, options, callback);

    if (request.socket) 
      onSocket(request.socket as any);
     else 
      request.prependOnceListener('socket', onSocket);
    

    request.prependOnceListener('response', onResponse);
    return request;

当您使用启用了 keepalive 的代理时,会出现这种方法的问题。在这种情况下,套接字可能会被重用,因此套接字已经建立了与远程主机的连接,并且不会发出套接字和查找事件(请注意,对于套接字事件,我们可以知道套接字事件如果设置了request.socket 属性,则不会发出)。

我怎样才能对查找事件做同样的事情?我可以检查套接字对象的哪个属性以确保主机已被解析并且不会发出查找事件?我应该使用localAddress/localPortremoteAddress/remotePort 属性还是socket.address() 方法?

【问题讨论】:

【参考方案1】:

所以,我做了一些测试,显然你可以做到:

if (Object.keys(socket.address()).length) 
    onLookup();
 else 
    socket.prependOnceListener('lookup', onLookup);

如果地址尚未解析,socket.address() 返回一个空对象,否则返回具有addressportfamily 属性的对象。

到目前为止它对我有用

【讨论】:

以上是关于套接字解析查找后立即触发回调的主要内容,如果未能解决你的问题,请参考以下文章

在打开套接字后立即将数据发送到套接字的替代方法

处理异步套接字(.Net)后仍然会调用回调

Windows 8 - .NET TCP AcceptAsync 回调未触发(被 Console.ReadLine() 阻止)

Java socket 读取后立即写入

Python Socket接收/发送多线程

Sailsjs:在 Sails 0.11 中,如何不使用带有套接字的 onConnect 生命周期回调