0

我在多设备应用程序上使用 TIdHTTP 组件(在 Rad Studio Tokyo 10.2.3 中构建)。我所做的只是将文件下载到我的本地应用程序文件夹(iOS)。我想确保它适用于 IPv6,但我没有看到 TIdHTTP 的“IPVersion”属性。我在 rad studio 的其他 indy 组件上看到它(例如 IdFTP)。

有没有办法在 TIdHTTP 组件的代码中设置 IPVersion?下面是我用来下载文件的代码片段。如果它在 IPv4 上失败,它应该接下来尝试 IPv6:

UnicodeString LFileName = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "myfile.txt");
TFileStream* fs = new TFileStream(LFileName, fmCreate);
Form1->TIdHTTP->ConnectTimeout = 8000;  // give it 8 seconds
Form1->TIdHTTP->ReadTimeout = 8000;

try
{
    UnicodeString URL = "http://myservername.com/myfile.txt";
    Form1->TIdHTTP->Get(URL, fs);
    Form1->TIdHTTP->Disconnect();  
    // ShowMessage("Good download via IPv4");
}
catch(const System::Sysutils::Exception &)
{
    try
    {
     Form1->TIdHTTP->Disconnect(); // clean up from IPv4 try
     UnicodeString URL = "http://[myservername.com]/myfile.txt";
     Form1->TIdHTTP->Get(URL, fs);
     Form1->TIdHTTP->Disconnect();  
     // ShowMessage("Good download via IPv6");

现在我只是在域名周围加上括号,希望这对 IPv6 有效……在我获得真正的仅 IPv6 网络设置(正在处理)之前,我不能确定。

更新:我刚刚有一个应用程序被 Apple Store 接受,它使用这种方法,很明显它通过了 IPv6 测试。供参考

4

1 回答 1

0

我发现了这个讨论,其中 Remy Lebeau 说:

TIdHTTP 仅从 URL 本身解析 IP 版本信息,因此如果您需要向 IPv6 目标(IP 地址或主机名)发送请求,则必须通过将 URL 的主机名部分包装在方括号中来告诉 TIdHTTP 使用 IPv6,例如:

s := idHTTP.Post('http://[IPv6 address or hostname]/resource', ...);

否则 TIdHTTP 使用 IPv4 代替。

根据 RFC 2732 和 3986,在 URL 中使用 IPv6 地址文字时,需要这种括号语法。但是当使用主机名时,没有这样的语法要求。连接到主机名需要 DNS 查找以发现主机的可用 IP 地址及其各自的 IP 版本,然后根据需要连接到这些地址,直到成功。

Indy 目前没有实现这种连接模型。它首先根据客户端的 IPVersion 属性分配一个套接字,然后执行适合该 IPVersion 的 DNS 请求,最后连接到 DNS 报告的第一个 IP 地址。这是 Indy 的一个已知限制,需要重新设计 Indy 的内部逻辑才能解决。但是,它可以在大多数 Indy 客户端组件中手动解决,方法是提前执行您自己的 DNS 查找,然后循环遍历结果,设置 Indy 的 Host 和 IPVersion 属性并在每次循环迭代时调用 Connect()。

但是,TIdHTTP 是一种特殊情况,因为它从请求的 URL 派生 Host 和 IPVersion 值,覆盖调用代码可能手动设置的任何内容。但是,也正是因为这种模型,它可能允许更新 TIdHTTP 以在内部执行其自己的 DNS 循环,而无需重写所有 Indy 的客户端组件以匹配。除了 Indy 目前没有实现返回主机名的所有 IP 地址的函数,只返回特定版本的第一个 IP 地址。在以跨平台方式将这样的功能添加到 Indy 之前,TIdHTTP 无法更新为自动检测 IPv4/IPv6 主机。

因此,这证实了我的方法应该使用方括号起作用(先尝试 IPv4,如果失败,然后再尝试 IPv6)。

此外,我在尝试 IPv6 之前编辑了我的代码以显示“断开连接”,以防 IPv4 留下一团糟。

于 2018-04-24T14:48:46.260 回答