71 lines
4.7 KiB
Markdown
71 lines
4.7 KiB
Markdown
# IP multicast
|
|||
|
|
|
||
|
|
Один контейнер принимает UDP-датаграммы на порту 9999 и пересылает их на multicast-адрес `224.0.2.0:10000`. Три контейнера-получателя присоединяются к этой группе и печатают полученные сообщения. В примере нет подтверждений, повторной передачи и восстановления пропусков.
|
||
|
|
|
||
|
|
## Запуск
|
||
|
|
|
||
|
|
Из корня репозитория перейдите в каталог примера и запустите контейнеры:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
cd materials/04-group-comm/seminar/ip_multicast
|
||
|
|
docker compose up --build -d
|
||
|
|
docker compose logs -f sender receiver1 receiver2 receiver3
|
||
|
|
```
|
||
|
|
|
||
|
|
Дождитесь сообщения `ready` от отправителя и каждого получателя. Последняя команда показывает журналы и занимает терминал. Следующие команды выполняйте во втором терминале из того же каталога.
|
||
|
|
|
||
|
|
Отправьте пробное сообщение через Python 3:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
python -c "import socket; s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM); s.sendto(b'probe',('127.0.0.1',9999)); s.close()"
|
||
|
|
```
|
||
|
|
|
||
|
|
При необходимости замените `python` на имя Python 3 в своём окружении. Убедитесь, что `probe` появился в журналах всех трёх получателей. Отправитель также печатает каждую пересылку. Имена сервисов в журнале позволяют различить получателей.
|
||
|
|
|
||
|
|
Если с хоста сообщения не доходят (нет `forwarded`), отправляйте из контейнера: `docker compose exec sender python -c "..."`.
|
||
|
|
|
||
|
|
## Эксперимент: получатель пропустил сообщение
|
||
|
|
|
||
|
|
До запуска предположите, какие получатели увидят `m1` и `m2` и получит ли вернувшийся участник пропущенные данные.
|
||
|
|
|
||
|
|
1. Остановите третьего получателя:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
docker compose stop receiver3
|
||
|
|
```
|
||
|
|
|
||
|
|
2. Отправьте `m1`:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
python -c "import socket; s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM); s.sendto(b'm1',('127.0.0.1',9999)); s.close()"
|
||
|
|
```
|
||
|
|
|
||
|
|
3. Верните третьего получателя:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
docker compose start receiver3
|
||
|
|
```
|
||
|
|
|
||
|
|
4. Дождитесь **нового** сообщения `ready` от `receiver3` и снова отправьте `probe`. Убедитесь, что третий получатель его видит.
|
||
|
|
5. Отправьте `m2`, заменив в команде `b'm1'` на `b'm2'`.
|
||
|
|
|
||
|
|
При штатной работе стенда `m1` увидят первый и второй получатели, а `m2` — все три. Третий получатель не получит `m1` задним числом: программа не хранит историю и не запрашивает пропущенные сообщения. UDP допускает потери и без отключения получателя; успешная проба не является доказательством гарантированной доставки.
|
||
|
|
|
||
|
|
Обсудите:
|
||
|
|
|
||
|
|
- Какие действия выполняет `IP_ADD_MEMBERSHIP` и где задаётся адрес группы?
|
||
|
|
- Где в программе можно было бы добавить подтверждения или восстановление пропусков?
|
||
|
|
- Почему получение сетевого пакета и надёжная доставка сообщения приложению — разные события?
|
||
|
|
|
||
|
|
Пустая UDP-датаграмма тоже является сообщением: `b''` не означает закрытие соединения. Можно отправить её и затем обычное сообщение, чтобы проверить, что оба процесса продолжают работу.
|
||
|
|
|
||
|
|
Повторный запуск контейнера в этом эксперименте иллюстрирует пропуск данных. В домашнем задании используется модель crash-stop: отказавшие процессы не возвращаются.
|
||
|
|
|
||
|
|
## Завершение
|
||
|
|
|
||
|
|
Остановите просмотр журналов сочетанием Ctrl+C, затем удалите контейнеры стенда:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
docker compose down
|
||
|
|
```
|