#unix-socket #binding #tcp-socket #sockets #unix #systemd

服务绑定

自动解析和绑定到 TCP、Unix 套接字和 Windows 命名管道

10 个版本 (5 个稳定)

3.0.0 2024 年 5 月 7 日
2.1.0 2024 年 4 月 18 日
2.0.0 2024 年 3 月 24 日
1.1.0 2022 年 11 月 9 日
0.1.1 2022 年 4 月 22 日

#275网络编程

Download history 354/week @ 2024-05-03 181/week @ 2024-05-10 142/week @ 2024-05-17 104/week @ 2024-05-24 115/week @ 2024-05-31 215/week @ 2024-06-07 61/week @ 2024-06-14 38/week @ 2024-06-21 22/week @ 2024-06-28 78/week @ 2024-07-05 147/week @ 2024-07-12 131/week @ 2024-07-26 58/week @ 2024-08-02 3/week @ 2024-08-09 89/week @ 2024-08-16

每月 281 次下载
用于 3 个 Crates(2 个直接使用)

MIT/Apache

27KB
450

service-binding

CI Crates.io

提供了一种方式,允许服务器和客户端以结构化格式描述它们的服务绑定和客户端端点。

此 Crates 自动解析和绑定到 TCP 套接字、Unix 套接字和 Windows 命名管道

设计上,此 Crates 非常精简,主要依赖于 std 中的内容(除 macOS launchd 服务绑定外)。

URI 方案绑定深受 Docker Engine 指定方案的影响。

use service_binding::{Binding, Listener};

let host = "tcp://127.0.0.1:8080"; // or "unix:///tmp/socket"

// parse the URI into a Binding
let binding: Binding = host.parse().unwrap();

// convert the binding into a Listener
match binding.try_into().unwrap() {
    #[cfg(unix)]
    Listener::Unix(listener) => {
        // bind to a unix domain socket
    },
    Listener::Tcp(listener) => {
        // bind to a TCP socket
    }
    Listener::NamedPipe(pipe) => {
        // bind to a Windows Named Pipe
    }
}

支持的方案

URI 格式 示例 描述 绑定 监听器 / 流
tcp://ip:port tcp://127.0.0.1:8080 TCP IP 地址 套接字 Tcp
tcp://address:port tcp://localhost:8080 具有地址解析的主机名 [^1] 套接字 Tcp
unix://path unix:///run/user/1000/test.sock Unix 域套接字 [^2] 文件路径 Unix
fd:// fd:// systemd 首次套接字激活 [^3][^4] 文件描述符 Unix
fd://<number> fd://3 精确的文件描述符数字 文件描述符 Unix
fd://<socket-name> fd://http 通过名称激活套接字 [^4] 文件描述符 Unix
npipe://<name> npipe://agent Windows 命名管道 [^5] 命名管道 命名管道

^[1] 绑定到第一个成功的地址(见 TcpListener::bind) [^2] 目前在Windows上通过 std 不可用(见 #271#56533) [^3] 等同于 fd:// 但如果传递了更多套接字则会失败 [^4] 仅为监听器 [^5] 转换为 \\.\pipe\test

示例

以下示例使用 clapactix-web,并使其能够使用Unix域套接字(包括systemd套接字激活)和绑定到TCP端口的常规TCP套接字组合运行服务器

use actix_web::{web, App, HttpServer, Responder};
use clap::Parser;
use service_binding::{Binding, Listener};

#[derive(Parser, Debug)]
struct Args {
    #[clap(
        env = "HOST",
        short = 'H',
        long,
        default_value = "tcp://127.0.0.1:8080"
    )]
    host: Binding,
}

async fn greet() -> impl Responder {
    "Hello!"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let server = HttpServer::new(move || {
        App::new().route("/", web::get().to(greet))
    });

    match Args::parse().host.try_into()? {
        #[cfg(unix)]
        Listener::Unix(listener) => server.listen_uds(listener),
        Listener::Tcp(listener) => server.listen(listener),
        _ => Err(std::io::Error::other("Unsupported listener type")),
    }?.run().await
}

systemd 套接字激活

此crate还支持systemd的 套接字激活。如果要解析的参数是 fd://,则返回的 Listener 对象将是一个包含systemd提供的监听器的 Unix 变体。

例如以下文件定义了一个套接字单元:~/.config/systemd/user/app.socket

[Socket]
ListenStream=%t/app.sock
FileDescriptorName=service-name

[Install]
WantedBy=sockets.target

当启用时,它将在 $XDG_RUNTIME_DIR 目录中创建一个新的套接字文件。当此套接字连接到systemd时,将启动服务;fd:// 读取正确的systemd环境变量并返回Unix域套接字。

服务单元文件 ~/.config/systemd/user/app.service

[Service]
ExecStart=/usr/bin/app -H fd://

由于套接字已命名(FileDescriptorName=service-name),因此也可以使用其显式名称选择它:fd://

launchd 套接字激活

在macOS上,尽管需要通过 fd:// 语法显式命名套接字,但launchd套接字激活也是可用的。

相应的 plist 文件(可以放置在 ~/Library/LaunchAgents 并通过 launchctl load ~/Library/LaunchAgents/service.plist 加载)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>EnvironmentVariables</key>
	<dict>
		<key>RUST_LOG</key>
		<string>debug</string>
	</dict>
	<key>KeepAlive</key>
	<true/>
	<key>Label</key>
	<string>com.example.service</string>
	<key>OnDemand</key>
	<true/>
	<key>ProgramArguments</key>
	<array>
		<string>/path/to/service</string>
		<string>-H</string>
		<string>fd://socket-name</string> <!-- activate socket by name -->
	</array>
	<key>RunAtLoad</key>
	<true/>
	<key>Sockets</key>
	<dict>
		<key>socket-name</key> <!-- the socket name here -->
		<dict>
			<key>SockPathName</key>
			<string>/path/to/socket</string>
			<key>SockFamily</key>
			<string>Unix</string>
		</dict>
	</dict>
	<key>StandardErrorPath</key>
	<string>/Users/test/Library/Logs/service/stderr.log</string>
	<key>StandardOutPath</key>
	<string>/Users/test/Library/Logs/service/stdout.log</string>
</dict>
</plist>

许可证

本项目根据您的选择受以下之一许可:

贡献

除非您明确声明,否则根据Apache-2.0许可证定义,您提交给此crate的任何有意贡献,都应按上述方式双许可,不附加任何额外条款或条件。

依赖项