2

我正在尝试在 Rust 中为一个简单的浏览器游戏制作一个 Web 服务器。我希望服务器能够通过 HTTPS 传递页面,还能够通过 WebSockets 进行通信。我打算把这个服务器放在 Heroku 上,但由于每个应用程序只允许一个端口,我必须让 WebSocket 服务器在与其他 HTTPS 代码相同的端口上运行。

似乎这对于像这样的 crate 是可能的rust-websocket,但是那个 crate 使用了一个过时的版本hyper并且似乎不再被维护。板条箱tokio_tungstenite是最新的。

问题是两者hyper都有tungstenite自己的 HTTP 协议实现,WebSockets 无法在两者之间进行转换。这意味着一旦 HTTPS 请求被任何一方解析hypertungstenite无法继续由另一方处理,因此您无法真正尝试连接 WebSocket 并匹配错误tungstenite并通过 处理它hyper,也不能您解析请求hyper并检查它是否是 WebSocket 请求并将其发送到tungstenite. 有没有办法解决这个问题?

4

2 回答 2

1

我认为应该可以做到这一点,tungstenite并且tokio-tungstenite允许您指定自定义标头(有帮助函数,前缀为hdr),因此取决于hyper您使用的版本,如果您可以将请求转换为某种形式,当可以提取标题,您可以将它们传递给tungstenite.

您可能还想尝试warpcrate,它构建在上面,hyper并且在底层使用tungstenitewebsocket 支持,所以如果您想编写自己的版本warp,您可以查看源代码(源代码可能包含关于如何使用hypertungstenite一起使用的提示)。

于 2018-11-02T11:28:35.697 回答
0

你可以做到,但它非常繁琐。您必须使用tokio-tungstenite,自己进行握手(检查标头,设置响应标头)并在运行时产生一个新的未来来处理 websockets 连接。可以通过使用最新版本的 hyper调用请求体来创建新的未来on_upgrade(),然后可以将连接传递tokio_tungstenite::WebSocketStream::from_raw_socket给以将其转换为 websockets 连接。

示例处理程序(请注意,这不会完全检查请求标头并假设我们想要升级):

fn websocket(req: Request<Body>) -> Result<Response<Body>, &'static str> {
    // TODO check other header
    let key = match req.headers().typed_get::<headers::SecWebsocketKey>() {
        Some(key) => key,
        None => return Err("failed to read ws key from headers"),
    };
    let websocket_future = req
        .into_body()
        .on_upgrade()
        .map_err(|err| eprintln!("Error on upgrade: {}", err))
        .and_then(|upgraded| {
            let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
                upgraded,
                tokio_tungstenite::tungstenite::protocol::Role::Server,
                None,
            );
            let (sink, stream) = ws_stream.split();
            sink.send_all(stream)
                .map(|_| ())
                .map_err(|err| error!("{}", err))
        });
    hyper::rt::spawn(websocket_future);
    let mut upgrade_rsp = Response::builder()
        .status(StatusCode::SWITCHING_PROTOCOLS)
        .body(Body::empty())
        .unwrap();
    upgrade_rsp
        .headers_mut()
        .typed_insert(headers::Upgrade::websocket());
    upgrade_rsp
        .headers_mut()
        .typed_insert(headers::Connection::upgrade());
    upgrade_rsp
        .headers_mut()
        .typed_insert(headers::SecWebsocketAccept::from(key));
    Ok(upgrade_rsp)
}
于 2019-04-12T22:47:04.873 回答