繁体   English   中英

有没有办法模拟 Socket 和 Connection 超时?

[英]Is there a way to simulate Socket and Connection timeout?

我有一段代码使用 HTTP 连接与第三方集成,它以不同的方式处理套接字超时和连接超时。

我一直在尝试模拟和测试第三方可能出现的所有场景。 能够通过连接到被服务器防火墙阻止的端口(例如端口 81)来测试连接超时。

但是我无法模拟套接字超时。 如果我的理解没有错,套接字超时与连续的数据包流相关,并且连接断开。 有没有办法可以模拟这个?

所以我们这里讨论的超时有几种,一种是连接到服务器(连接超时),另一种是在一段时间内没有通过套接字发送或接收数据时发生超时(空闲超时)。

节点 sockets 有一个套接字超时,可用于综合连接超时和空闲超时。 这可以通过将套接字超时设置为连接超时,然后在连接时将其设置为空闲超时来完成。

例子:

        const request = http.request(url, {
            timeout: connectTimeout,
        });
        request.setTimeout(idleTimeout);

这是因为选项中的超时在创建套接字时立即设置, setTimeout function 在连接时在套接字上运行!

无论如何,问题是关于如何测试连接超时。 好的,让我们先停止空闲超时。 我们可以通过一段时间不发送任何数据来简单地测试一下,这会导致超时。 查看!

连接超时有点难以测试,首先想到的是我们需要一个连接的地方,不会出错,但也不能连接。 这会导致超时。 但是我们到底如何在节点中模拟呢?

如果我们跳出框框思考一下,那么我们可能会发现这个超时时间大约是连接所需的时间。 为什么连接需要这么长时间并不重要。 我们只需要延迟连接所需的时间。 这不一定是服务器的事情,我们也可以在客户端上做。 毕竟这是连接的部分,如果我们可以在那里延迟它,我们可以测试超时。

那么我们如何才能延迟客户端的连接呢? 好吧,我们可以使用 DNS 查找。 在建立连接之前,完成了 DNS 查找。 如果我们简单地将其延迟 5 秒左右,我们可以很容易地测试连接超时。

这就是代码的样子:

import * as dns from "dns";
import * as http from "http";

const url = new URL("http://localhost:8080");

const request = http.request(url, {
    timeout: 3 * 1000, // connect timeout
    lookup(hostname, options, callback) {
        setTimeout(
            () => dns.lookup(hostname, options, callback),
            5 * 1000,
        );
    },
});
request.setTimeout(10 * 1000); // idle timeout

request.addListener("timeout", () => {
    const message = !request.socket || request.socket.connecting ?
        `connect timeout while connecting to ${url.href}` :
        `idle timeout while connected to ${url.href}`;

    request.destroy(new Error(message));
});

在我的项目中,我通常使用我注入的代理。 然后代理进行延迟查找。 像这样:

import * as dns from "dns";
import * as http from "http";

const url = new URL("http://localhost:8080");

const agent = new http.Agent({
    lookup(hostname, options, callback) {
        setTimeout(
            () => dns.lookup(hostname, options, callback),
            5 * 1000,
        );
    },
});

const request = http.request(url, {
    timeout: 3 * 1000, // connect timeout
    agent,
});
request.setTimeout(10 * 1000); // idle timeout

request.addListener("timeout", () => {
    const message = !request.socket || request.socket.connecting ?
        `connect timeout while connecting to ${url.href}` :
        `idle timeout while connected to ${url.href}`;

    request.destroy(new Error(message));
});

快乐编码!

“连接超时”确定建立 TCP 连接可能需要多长时间,这一切都发生在任何 HTTP 相关数据通过线路发送之前。 通过连接到阻塞的端口,您只测试了部分连接超时,因为没有建立连接。 通常,本地网络上的 TCP 连接的创建(建立)非常快。 但是当连接到世界另一端的服务器时,建立 TCP 连接可能需要几秒钟。

“套接字超时”是一个有点误导性的名称 - 它只是确定您(客户端)将等待来自服务器的答案(数据)的时间。 换句话说, Socket.read() function 在等待数据时会阻塞多久。

正确测试这些功能涉及创建服务器套接字或(HTTP)网络服务器,您可以将其修改为非常慢。 描述如何创建和使用服务器套接字进行连接超时测试(如果可能的话)在这里回答太多了,但套接字超时测试是一个常见问题 - 参见例如这里(我刚刚搜索了“模拟 web 服务器用于测试超时") 这导致了像MockWebServer这样的工具。 “MockWebServer”可能也有测试连接超时的选项(我没有使用“MockWebServer”),但如果没有,另一个工具可能有。

最后一点:最好您正在测试第三方 HTTP 库的超时设置使用情况,即使这需要一些努力。 可能发生的最糟糕的情况是,库以某种方式未使用代码中的套接字超时设置,并且使用了“永远等待”的默认套接字超时。 这可能会导致您的应用程序无缘无故地什么都不做(“挂起”)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM