Сокет не принимает данные: не тот тип
Тип сокета должен совпадать с тем, что ожидает программа: потоковый для TCP и unix-потоков, датаграммный для UDP. При несовпадении сокет открывается, а данные до службы не доходят.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Объявлен потоковый сокет для службы, работающей с UDP
Служба ждёт датаграммы, а systemd передаёт ей слушающий потоковый сокет. Обмена не происходит.
-
Программа не умеет работать с переданным сокетом
Даже верный тип не поможет, если программа открывает сокет сама. Тогда сокет-активация лишняя.
-
Смешаны оба типа в одном сокете
Объявление и потокового, и датаграммного адреса означает два дескриптора. Программа, ожидающая один, запутается.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Объявленные адреса и их типы.
systemctl show myapp.socket -p ListenСлушает ли адрес и какого типа сокет.
sudo ss -tulnp | grep портРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- Служба ждёт датаграммы, а systemd передаёт ей слушающий потоковый сокет. Обмена не происходит.
- Как проверить
-
Посмотрите тип сокета и что слушает служба.
systemctl show myapp.socket -p Listen sudo ss -ulnp | grep 514
- Как исправить
-
Замените параметр на датаграммный:
ListenDatagram=вместоListenStream=.
- Почему происходит
- Даже верный тип не поможет, если программа открывает сокет сама. Тогда сокет-активация лишняя.
- Как проверить
-
Посмотрите, что программа делает при запуске.
journalctl -u myapp.service -n 20 --no-pager
- Как исправить
- Откажитесь от сокет-активации для такой программы: пусть слушает сама.
- Почему происходит
- Объявление и потокового, и датаграммного адреса означает два дескриптора. Программа, ожидающая один, запутается.
- Как проверить
-
Посмотрите все объявления.
systemctl cat myapp.socket | grep -i listen
- Как исправить
- Оставьте один тип или задайте имена дескрипторов, чтобы программа их различала.
Пример вывода
Для UDP-службы объявлен потоковый сокет. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
$ systemctl show mysyslog.socket -p Listen
Listen=[::]:514 (Stream)
$ sudo ss -ulnp | grep 514
# пусто: датаграммный сокет никто не открыл
Связанные ошибки
- Сокет без Listen: unit загружен, но ничего не слушает В .socket не задан ни один параметр Listen…= — сокет не принимает соединения. Как объявить адрес прослушивания.
- Служба не получает сокет при сокет-активации Сокет активен, служба запускается, но не находит переданный дескриптор. Разбор: Accept, FileDescriptorName, соответствие имён.
- Соединения через сокет-активацию висят и не закрываются Клиенты уходят, соединения остаются: проверка живости соединений не включена.
- Сокет слушает только IPv6 или только IPv4 неожиданно Клиенты по одному из протоколов не подключаются: поведение двойного стека задаётся отдельным параметром.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- Automount: каталог монтируется не вовремя или отваливается Автомонтирование через .automount: как работает TimeoutIdleSec, почему ресурс отваливается и когда лучше обычный .mount.
- Bad file descriptor в журнале службы Ошибка 9 при операции с файлом: дескриптор закрыт или не тот. Разбор для служб и сокет-активации.
- Broken pipe в журнале службы Запись в закрытый канал или соединение: клиент отключился, обработчик завершился, конвейер разорван.
Источники
-
systemd.socket(5)
Типы сокетов и соответствующие параметры Listen…. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено потоковым сокетом для службы, ожидающей датаграммы.