UDP 守护进程的 systemd-activate 套接字激活

systemd-activate socket activation for UDP daemons

我喜欢在开发过程中使用 systemd-activate(8) 测试 套接字激活的守护进程, 然而,它似乎只监听 TCP 连接:

% /usr/lib/systemd/systemd-activate -l 5700 ./prog
Listening on [::]:5700 as 3.

% netstat -nl |grep 5700
tcp6       0      0 :::5700             :::*             LISTEN 

我正在使用处理数据报 (UDP) 的程序。如何让 systemd-activate 监听 UDP 端口?或者有没有 使用其他工具执行此操作的简单方法,无需费心制作和安装 systemd 单元文件?

我不确定 systemd-activate 是否有办法做到这一点。

您可能想要使用一些 .service 单元文件和一个 .socket 具有依赖关系的单元文件。在 .socket 单元中,您将描述 ListenDatagram= 选项。有关详细信息,请参阅 here

我最终编写了一个简单的 C 程序来完成这项工作;下面的代码(public 域)。

用法是:

./a.out <port-number> <prog> [<arg1> ...]

该程序在 <port-number> 上打开一个 UDP 套接字,设置 systemd 套接字激活的守护进程期望的环境变量,然后使用后面的任何参数执行 <prog>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>

int main(int argc, char **argv) {
    if (argc < 2) {
        printf("no port specified\n");
        return -1;
    }
    if (argc < 3) {
        printf("no program specified\n");
        return -1;
    }

    uint16_t port = htons((uint16_t) strtoul(argv[1], NULL, 10));
    if (port == 0 || errno) {
        printf("failed to parse port: %s\n", argv[1]);
        return -1;
    }

    /* create datagram socket */
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        printf("failed to open socket; errno: %d\n", errno);
        return -1;
    }

    struct sockaddr_in sa;
    sa.sin_family = AF_INET;
    sa.sin_port = port;
    sa.sin_addr.s_addr = INADDR_ANY;

    /* bind socket to port */
    int r = bind(fd, (struct sockaddr *) &sa, sizeof(struct sockaddr_in));
    if (r < 0) {
        printf("bind failed; errno: %d\n", errno);
        return -1;
    }

    /* execute subprocess */
    setenv("LISTEN_FDS", "1", 0);
    execvp(argv[2], argv + 2);
}

这是最近添加到 systemd-activatehttps://github.com/systemd/systemd/pull/2411,并且在发布时将成为 systemd-229 的一部分。