Мне нравится использовать 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?

1
frasertweedale 25 Дек 2015 в 09:18

3 ответа

Лучший ответ

В итоге я написал для этого простую программу на языке C; код ниже (общественное достояние).

Использование:

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

Программа открывает сокет UDP на <port-number>, устанавливает переменные среды, которые ожидают демоны, активируемые сокетами 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);
}
0
frasertweedale 27 Дек 2015 в 00:26

Я не уверен, что есть способ сделать это с помощью systemd-activate.

Вы можете использовать некоторый файл модуля .service и файл модуля .socket с зависимостями. В блоке .socket вы опишите вариант ListenDatagram=. Дополнительные сведения см. здесь.

0
Sergey Kanaev 26 Дек 2015 в 15:45

Это недавно было добавлено в systemd-activate: https://github.com/systemd/systemd/ pull / 2411 и будет частью systemd-229, когда он будет выпущен.

1
zbyszek 10 Фев 2016 в 01:16