如何在测试公共代理时可靠地重现curl_multi超时问题

10
相关信息:GitHub上的3602问题 我正在开展一个收集和测试公共/免费代理的项目,并发现当我使用curl_multi接口测试这些代理时,有时会出现许多28(超时)错误。如果我单独测试每个代理,就不会出现这种情况。
问题在于,这个问题无法可靠地再现,并且它并不总是出现,可能是curl中的某些问题或其他问题。
不幸的是,我不是一个深入的网络调试器,我不知道如何在更深层次上调试这个问题,但是我编写了两个C测试程序(其中一个最初由Daniel Stenberg编写,但我修改了其输出格式与另一个C程序相同)。这两个C程序使用curl测试407个公共代理。
1.使用curl_multi接口进行测试(存在问题) 2.使用多个线程上的curl,每个curl在一个线程上运行。(没有问题) 这是我编写的两个C程序用于测试我不是C开发人员,因此请告诉我您在两个程序中注意到的任何错误。

这是我一个月前用来复现问题的原始PHP类

这是两个C程序测试结果。您可以注意到使用curl_multi超时的测试,而由curl线程产生的超时是稳定的(约有407个代理中的50个正在工作)。

这是测试结果的示例。 请注意第4和第5列,看看curl线程大约超时了约170次并成功连接了约40次。其中,curl_multi没有成功连接,407个代理中超时了约300次。

column(1) : #
column(2) : time(UTC)
column(3) : total execution time (seconds)
column(4) : no error 0 (how many requests result in no error CURLE_OK)
column(5) : error 28 (how many requests result in error 28 CURLE_OPERATION_TIMEDOUT)
column(6) : error 7 (how many requests result in error 7 CURLE_COULDNT_CONNECT)
column(7) : error 35 (how many requests result in error 35 CURLE_SSL_CONNECT_ERROR)
column(8) : error 56 (how many requests result in error 56 CURLE_RECV_ERROR)
column(9) : other errors (how many requests result in errors other than the above)
column(10) : program that used the curl
column(11) : cURL version

c(1)    c(2)           c(3)c(4)c(5)c(6)c(7)c(8)c(9) c(10)                  c(11)
267 2019-3-28 01:58:01  40  43  176 183 1   4   0   C (curl - threads) (Linux Fedora)   7.59.0
268 2019-3-28 01:59:01  30  0   286 110 1   10  0   C (curl-multi one thread) (Linux Fedora)    7.59.0
269 2019-3-28 02:00:01  30  46  169 181 1   8   2   C (curl - threads) (Linux Fedora)   7.59.0
270 2019-3-28 02:01:01  31  0   331 74  1   1   0   C (curl-multi one thread) (Linux Fedora)    7.59.0
271 2019-3-28 02:02:01  30  42  173 186 1   4   1   C (curl - threads) (Linux Fedora)   7.59.0
272 2019-3-28 02:03:01  30  0   277 116 1   13  0   C (curl-multi one thread) (Linux Fedora)    7.59.0

为什么curl_multi在大多数连接上超时不一致,而curl-threads从未出现这种情况?
我下载了Wireshark并使用它来捕获两个C程序运行时的流量,我还将流量过滤到2个C程序使用的代理列表,并将文件保存在GitHub上。

curl-threads程序(预期行为)

407个代理中63个成功连接,158个连接超时。

curl_multi程序(预期的行为)

407个代理中0个成功连接,272个连接超时。

您可以使用Wireshark打开.pcapng文件,并查看在我的计算机上记录的流量,同时包括预期/非预期的行为。我过滤了407个代理IP的流量,并在30秒的curl限制后将Wireshark保持打开状态一段时间,因为我注意到仍有一些数据包出现。我不懂Wireshark和这种网络层次,但我认为这可能会有用。


关于带宽的说明:

在Wireshark中打开curl_threads程序的.pcapng文件(正常行为),并转到“统计”>“对话”。您将看到一个类似于这样的窗口

enter image description here

我已经复制了数据并将它们保存在这里的GitHub上,现在计算从A->B和B->A发送的字节数的总和

正常工作所需的全部带宽约为692.8 KB。


请查看我在 GitHub 问题上的评论。另外,在您的代码中,最好启用 CURLOPT_VERBOSE。为了保持一致性,考虑使用 badger 在 GitHub 上提供的 C 版本。 - S.S. Anne
你好 @JL2210,我已经在GitHub上回复了你的评论。关于C版本,我刚刚添加了聚合测试结果并以与线程程序相同的格式将其打印到文件中的功能,这样我就可以将两个程序的结果放在同一个文件中进行比较。 - Accountant م
1
@JL2210 非常感谢您的编辑,我会检查它们。*"您的网络上是否有防火墙?或者有什么可能限制出站连接的东西"* 如果我的网络有问题,那么curl-threads程序也会有问题,但是线程程序运行良好,而curl-multi程序有时会出现问题。 - Accountant م
抱歉...不管怎样,这对你来说怎么样? - S.S. Anne
1
@JL2210 同样的问题,我写了一个小的 C 程序,使用 curl 在一个线程上进行 1 次请求,它可以正常工作。但是 curl_multi 仍然会产生 28 超时错误,所以我不再使用它。 - Accountant م
显示剩余3条评论
2个回答

2

我已经得到了可重复的行为并在等待GitHub上的badger回复。尝试运行像Ettercap这样的程序以获得更多信息。

Translated:

我已经发现了可重复的问题,正在等待GitHub上的badger回复。尝试运行类似于Ettercap这样的程序以获取更多信息。


我使用Wireshark捕获了正常和非正常行为的流量,并保存了Wireshark的.pcapng文件,以便任何人都可以分析发生了什么。我将更新问题和GitHub问题,希望这也能有所帮助。 - Accountant م
1
好的。我不能使用Wireshark,因为它需要Qt5,而这个软件对我来说还没有构建成功。如果我有任何更新,我会在这里提供更多信息。 - S.S. Anne
所以回答你的问题:在非常慢/低带宽的网络上运行这些测试。那么,为什么线程程序在完全相同的机器和网络上按预期工作?!它们始终表现出成功连接方面的一致性 curl-threads>43, curl-multi>0, curl-threads>46, curl-multi>0, curl-threads>42, curl_multi>0, ... - Accountant م
我在一个慢速/低带宽网络上一直收到这个错误,那么这不就回答了你的问题吗? - S.S. Anne
我在一个慢速/低带宽网络上一直遇到这个错误,这难道不回答了你的问题吗?不是的James,因为线程程序是正常工作的!当然,在非常慢的网络上,两者都不会工作,但在良好的连接下,只有curl_multi程序有时会显示问题,甚至在一个拥有500 Mbps上行链路的生产服务器上也能重现。 - Accountant م
显示剩余9条评论

1
在我看来,你不是与curl本身有问题,而是同时向代理服务器做太多连接,如果连接被拒绝,你可能会被永久或一段时间列入黑名单。
通过从当前IP运行curl并进行统计来检查:建立了多少连接,拒绝了多少连接,超时了多少连接。多次执行并收集平均值。然后将服务器更改为具有不同IP的其他服务器,并检查您在那里的统计数据。第一次运行时,您应该有更好的统计数据,但如果您在新IP上重复测试,则可能只会变得更糟。 一个好主意可能是不使用所有代理池来连接以进行统计,而是选择其中一部分并在实际IP上进行检查,并在新IP上重复该检查,因此,如果原因是您滥用服务,则不会在所有代理中列入黑名单,但仍将在新IP上测试下一组“未触及”的代理(如果确实如此)。 请注意,即使代理的IP位于不同的位置,它们也可能属于同一服务提供商。这可能对其所有代理服务器都有一个滥用列表,因此,如果您在一个国家的请求量不好,甚至在连接到另一个国家的代理之前,您也可能会在其他国家被阻止。
如果您仍然想检查这是否不是curl,则可以设置一个具有多个服务器的测试环境。您可以将此测试环境传递给curl维护者以便他可以复制该错误。 您可以使用docker创建10、20或100个代理服务器并连接到它们,以查看curl是否存在问题。
你需要 docker 它可以在Win/Mac/Linux上安装
其中之一 代理镜像 用于创建代理
为容器创建网络 教程 (桥接应该没问题)
将容器附加到网络 --network
对于每个代理容器,最好设置它们的 --ip
通过挂载错误日志/配置文件/目录并使用 --volume,使每个代理容器都能够读取配置和写入错误日志(如果发生断开连接,您可以读取原因)
所有代理容器都应该在运行
你可以通过两种方式连接到在容器内运行的代理。如果你想要在这些容器之外使用curl,那么你需要通过-p将这些代理的端口从容器暴露到外部世界(在你的情况下是curl)。
或者,你可以使用另一个包含linux + curl的容器镜像。例如Alpine linux + curl,并以与代理相同的方式将其连接到相同的网络。这样做就不需要发布(暴露)代理的端口,也不需要考虑应该为特定代理公开哪个端口号。
在每个步骤中,你都可以发出一个命令。
docker ps -a

查看所有容器及其状态。

如果您的容器出现错误并退出,停止并删除所有容器(不是它们来自的镜像)。

docker stop $(docker ps -aq) && docker rm $(docker ps -aq)

或者停止并从列表中删除特定的容器。
docker stop <container-id>
docker rm <container-id>

查看所有连接到桥接网络(默认)的容器
docker network inspect bridge

如果您确认与本地代理的连接存在问题,那么这是curl维护者可以复制的内容。
只需将所有命令(如上所述)放入文件中以创建所有代理并将它们连接到网络等,例如replicate.sh脚本开始。
#!/bin/sh

and your comands here

保存该文件并输入以下命令。
chmod +x ./replicate.sh

使其可执行。

您可以运行它来检查是否一切都按预期工作。

./replicate.sh

并向curl的维护者发送信息,以复制您遇到问题的环境。 如果您不喜欢输入许多像doker run这样的命令来运行代理,可以使用docker compose,它允许您在一个文件中定义整个测试环境。 如果您运行大量容器,您可以限制每个容器消耗的资源,例如memory,这可能有助于处理如此多的代理。

非常感谢您的时间,Jimmix。我被列入黑名单的可能性已经被排除了,因为curl-threads程序在相同的网络中运行得非常好,而curl-multi程序却无法工作。幸运的是,在我提供的测试结果中,我提供了一个样本,curl-multi根本没有工作(0个成功连接)。请检查我在答案中提供的样本中的第4列,您会看到curl-threads>43,curl-multi>0,curl-threads>46,curl-multi>0,curl-threads>42,curl_multi>0,...(每个测试之间的时间跨度为1分钟)。 - Accountant م
查看 C 程序的 readme,如果您想要自己进行测试,您将会知道如何进行测试并且明白我的意思。 - Accountant م
非常感谢您提供Docker建议,但我认为我不需要它,因为问题已经可以在当前安装上复现,只是不总是能够复现。我从未使用过Docker,但当我尝试使用Docker时,我会将您的答案收藏为参考。谢谢。 - Accountant م
1
@会计师,很高兴您重现了错误。我阅读了您提供的自述文件和 Cron 作业。您可能也喜欢使用 Cron 每隔奇数/偶数分钟运行一次作业的这种方式 - Jimmix
1
这不是黑名单问题,因为代理不知道他是否在使用单线程的curl_multi API,还是每个curl_easy句柄都有一个线程,而且只有在他使用单线程的curl_multi API时才会出现此问题,当他使用1线程/易处理器时,不会发生这种情况。如果这是黑名单问题,那么在使用1线程/句柄时也会发生,但事实并非如此。 - hanshenrik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接