2

我有一个简单的 HTTP 服务器,在端口 3005 上使用路由器和 Iron。它没有做任何令人兴奋的事情。我相信它只是回应了请求,但细节并不重要。

我还制作了一个简单的客户端,使用 hyper 的客户端模块向服务器发送请求。

每当我在 IPv4 上运行服务器时localhost,我都没有遇到任何问题。我可以用我的客户和 curl 查询它。如果我在我的 IPv6 上启动服务器localhost(我使用的是缩短版本::1),我只能使用 curl 访问服务器。

这表明服务器运行正常并响应,但我Client访问它的超代码失败,报告:

Err(Io(Error { repr: Custom(Custom { kind: Other, error: StringError("未能查找地址信息:名称或服务未知") }) })) 线程'main'在'调用Result::unwrap()一个Err值时恐慌: io(Error { repr: Custom(Custom { kind: Other, error: StringError("无法查找地址信息:名称或服务未知") }) })', /checkout/src/libcore/result.rs: 860

我用来发送 POST 请求的代码如下:

let addr = "http://[::1]:3005/message";
let mut res = self.client.post(addr).body(s.as_str()).send().unwrap();

s我要发送的一些有效载荷在哪里。

我也尝试了扩展的 IPv6 地址 ( [0:0:0:0:0:0:0:1]),我得到了同样的错误。

我还尝试了不带括号的缩短和扩展 IPv6 地址。我得到带有扩展地址的“无效端口-”和带有缩短地址的“空主机”。

要重现此行为,您可以使用这些小示例(取消注释注释行以接收错误):

服务器

extern crate iron;

use iron::prelude::*;
use iron::status;

fn hello_world(_: &mut Request) -> IronResult<Response> {
    println!("Recvd a request");
    Ok(Response::with((status::Ok, "Hello World!")))
}

fn main() {
    let port = 3000;
    //let addr = format!("{}:{}", "[::1]", port);
    let addr = format!("{}:{}", "localhost", port);

    println!("Server opened on {}", addr);

    Iron::new(hello_world).http(addr).unwrap();
}

客户

// hyper 0.10.13
extern crate hyper;

use hyper::*;
use std::io::Read;

fn main() {
    let client = Client::new();
    //let mut res = client.get("http://[::1]:3000/").send().unwrap();
    let mut res = client.get("http://localhost:3000/").send().unwrap();

    let mut s = String::new();
    res.read_to_string(&mut s).unwrap();

    println!("response contained: {}", s);
}

客户端V2

// For people that want to try with hyper 0.11.X
extern crate futures;
extern crate hyper;
extern crate tokio_core;

use std::io::{self, Write};
use futures::{Future, Stream};
use hyper::Client;
use tokio_core::reactor::Core;

fn main() {
    let mut core = Core::new().unwrap();
    let client = Client::new(&core.handle());

    let uri = "http://[::1]:3000/".parse().unwrap();
    let work = client.get(uri).and_then(|res| {
        println!("Response: {}", res.status());

        res.body().for_each(|chunk| {
            io::stdout()
                .write_all(&chunk)
                .map(|_| ())
                .map_err(From::from)
        })
    });

    core.run(work).unwrap();

}

注1:

您需要 hyper 0.10.X 才能运行此代码。就我而言,我使用的是 0.10.13

笔记2:

我正在发送没有有效负载的 GET 请求,以抽象出无关的功能位。

注3:

看起来 hyper 0.10.X 和 hyper 0.11.X 处理 IPv6 服务器的方式不同。Hyper 0.10.X 给出了上述错误,而 0.11.X 给出了 Response Code 400 Bad Request

4

1 回答 1

0

IPv6 支持似乎是以前和当前版本的 hyperium/hyper (<=0.11.23)的问题

开发人员建议为使用 hyper 0.11.X 的客户端使用 Reqwest crate,但由于 Reqwest 基于 hyper 构建,结果将是相同的。


到目前为止,我发现的解决方案是使用 cURL 的绑定来处理 Rust,因为 cURL 似乎足够健壮。这是我编写客户端的代码,该客户端将简单的 GET 请求发送到 IPv6 服务器地址。

客户

extern crate curl;
use std::io::{stdout, Write};
use curl::easy::Easy;

fn main() {
    let mut easy = Easy::new();

    easy.url("https://[::1]:3000").unwrap();
    easy.write_function(|data| {
        stdout().write_all(data).unwrap();
        Ok(data.len())
    }).unwrap();

    easy.perform().unwrap();
}

这不是最漂亮的解决方案,因为它使用了一个内置于 C 中的库,这是一种不安全的语言,但在出现更好的替代方案之前,它是一个很好的解决方法。

于 2018-03-28T16:56:21.307 回答