检测TcpStream的传入协议

Rae*_*isi 1 sockets websocket rust tungstenite

我的服务使用套接字通信收集并显示一些统计信息。一些客户端使用 WebSocket 协议通过 Web 浏览器连接到它,而其他客户端则使用使用常规套接字的 Windows 服务。

我这样创建了一个监听端口:

let on = "0.0.0.0:8081";
let server = std::net::TcpListener::bind(on)?;

while let Ok((stream, _)) = server.accept() {
  let peer_adr = stream.peer_addr().unwrap();
  if peer_adr.to_string().starts_with("127.0.0") {
     // socket
  } else {
     // web socket
     let ws = tungstenite::accept(stream)?;
  }
}
Run Code Online (Sandbox Code Playgroud)

我尝试过 IP 检查来检测客户端的类型,这对于生产来说是不可接受的。

我的问题是:

  1. 有没有更好的实现方式?
  2. 是否有任何标准方法来检测每个传入流的类型?(就像是stream.protocol.start_with("ws")

环境

Rust version: `1.74 - stable`
Extra crate: `tungstenite = { version = "0.20" }`
Run Code Online (Sandbox Code Playgroud)

Ste*_*ich 5

不存在“传入”协议之类的东西。它是一个应用程序协议,有无数个。虽然许多人从客户端发送数据开始(如 HTTP、SIP 等),但其他人则期望服务器发送第一个应用程序数据(如 SMTP、FTP、IMAP 等)。这意味着要处理任意应用程序协议,不能只侦听传入数据,因为如果客户端期望对等方首先开始发送,则不会有任何数据到来。

除此之外,当今许多协议在应用程序级别的传输中使用加密,通常使用 TLS。虽然某些协议将在不加密的情况下启动,然后升级(例如 SMTP 中的 STARTTLS),但许多协议将直接从 TLS 握手开始,这从客户端发送 ClientHello 开始。ClientHello 中没有或几乎没有指示符可以区分协议 - 有 ALPN 扩展,但这仅允许非常粗略地检测可能的应用程序协议。

简而言之:如果您只有一组非常有限的可能协议,那么您也许可以根据这组有限的协议编写自定义检测器。但前提是这些协议可以与客户端发送的第一个数据清楚地区分,而客户端不希望将数据发送到服务器。因此,这实际上取决于您的实际用例,并且没有涵盖所有可能协议的通用检测。