03.25 Ведение совместного проекта
ВНИМАНИЕ - Упражнения для этого занятия не будут работать под WSL, поскольку они требуют захода на машину извне, а виртуальная машина WSL находится за NAT-ом.
HTTP-сервер для бедных:
python3 -m http.server
Посмотреть на http://localhost:8000
- Простой способ узнать IP, если работает DNS:
Если DNS не работает или hostname == "localhost":
Пояснение: .connect() для UDP-сокета настраивает поле адрес_отправителя:порт_отправителя, но собственно соединения не устанавливает. адрес_отправителя при этом определяется маршрутизацией — это IP того интерфейса, через который пойдёт передача.
HTTP-сервер, который выводит IP адрес, а не 0.0.0.0
Изучить Модуль http.server
Подсказка: нужна только функция test()
Написать простой http-сервер httpsrv.py порт, который:
- Принимает единственный параметр — порт
При старте вместо http://0.0.0.0:8000/ выводит найденный IP (чтобы поделиться с товарищами)
Подсказки — параметры функции test():
BaseHTTPRequestHandler не достаточно, нужен SimpleHTTPRequestHandler
port — порт
bind — адрес
ServerClass.address_family можно не трогать
- Проверить, работает ли: скачать файл из каталога
Групповая разработка: precious source + committer
- Разбиться на пары. Работа каждого человека в паре идентична
Публикация репозитория
Создать пустой bare репозиторий public/myrepo (+посмотреть, как он устроен)
Настроить репозиторий для публикации (скопировать или переименовать хук, который будет запускаться при обновлении, заодно глянуть внутрь него — там должна запускаться команда git update-server-info)
Опубликовать с помощью httpsrv.py каталог public
Открыть новый терминал. Склонировать public/myrepo (не по http, потому что нужен доступ на запись)
1 $ git clone public/myrepo myrepo
Сделать в myrepo какие-то изменения (например, скопировать туда файл httpsrv.py), закоммитить и запушить
- Сообщить адрес, порт и имя опубликованного репозитория товарищу и узнать у него адрес, порт и имя его публичного репозитория
Публичный репозиторий для совместной разработки
По аналогии с предыдущим создать пустой bare репозиторий public/hisrepo и настроить в нём hooks/post-update
Склонировать public/hisrepo в hisrepo
- Добавить репозиторий товарища в качестве второго remote:
- Помержить пустую историю с авторской, добавить какие-то изменения, закоммитить,i
Результат прометить аннотированным тегом "fixes" и запушить к себе в public/hisrepo
- Зарегистрироваться как коммиттер в репозитории товарища и зарегистрировать товарища как коммиттера
- Сообщить товарищу адрес, порт и имя репозитория, в котором вы опубликовали изменения и узнать у него ту же информацию
В своём репозитории добавить в качестве второго remote репозиторий с изменениями от товарища, и помержиться с ними:
- Принять и отправить pull-реквест!
- Узнать у товарища имя тега, помечающего обновления и сообщить ему имя своего аналогичного тега
С помощью git log убедиться, что изменения пришли, опубликовать их и т. д.
- Разминка перед многопользовательским MUD
Заставляем работать Тупой netcat и Чат сервер из позапрошлой лекции
По аналогии с примером командной строки, в которую время от времени спамит второй поток вычислений, написать более удобный клиент к общему чату:
- В командной строке должны поддерживаться две команды:
hi — шлёт сообщение "Hello everybody" (с помощью .sendall())
say сообщение — шлёт сообщение (с помощью .sendall())
Приём сообщений делать в отдельном треде (с помощью .recv(1024))
- В командной строке должны поддерживаться две команды:
Д/З
Задача_1. Многопользовательский MUD (multiuser multiuser dungeon)
Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит. Работайте на ветке work.
- Сделайте (наконец-то!) MUD многопользовательским. Подробности ниже.
- Многосессионность (поддержку работы с одним сервером одновременно нескольких клиентов) реализуйте по схеме "коровьего чата" из лекций.
- Именованные сеансы:
При подключении клиента к серверу, клиент передаёт серверу имя пользователя (строка без пробелов, поступает клиенту при запуске - python mymud.py username).
- Сервер проверяет, что подключенного пользователя с таким именем ещё нет; если есть - отказывает в подключении; если нет, то создает подключение (сообщая об этом клиенту) и запоминает имя пользователя.
- Асинхронность работы клиента с сервером:
- после отправки сообщения серверу, клиент НЕ ждёт ответа от сервера
- все сообщения от сервера клиенту _после_ успешного подключения - "асинхронные", т.е. принимаются параллельно работе пользователя с командной строкой
- все сообщения от сервера клиенту предназначены ДЛЯ ВЫВОДА "as is", никакого разбора в духе "набор параметров от сервера к клиенту" теперь не нужно; т.е. клиент отправляет команды на сервер без ожидания ответа и без "понимания", что сообщения от сервера приходят в ответ на конкретные команды
схема параллельного ожидания сообщений и обработки пользовательского ввода - см. лекцию (раздел "Cmd и асинхронные сообщения")
- важно: после получения от сервера (и вывода) сообщения, клиент должен показать командную строку с набранным (но не введённым) пользователем текстом, чтобы результат ввода не исчезал (опять см. лекцию)
- Частичная неделимость обработки пользовательской команды на сервере (для ограничения гонок):
- помним, что сервер последовательный
- получив команду от клиента, сервер обрабатывает её сразу (а не планирует обработку через async)
- отправку сообщения клиенту (клиентам) сервер осуществляет асинхронно
- Широковещательные сообщения от сервера клиентам:
- сообщения о "знаковых событиях" сервер рассылает всем клиентам, в духе коровьего чата (где он транслирует всем клиентам полученное от клиента сообщение)
- знаковые события:
- атака на монстра (сообщать: кто атаковал (имя пользователя), чем, какого монстра, сколько очков здоровья снёс, сколько о.з. осталось; если монстр убит, то сообщить об этом [чтобы клиентам не пришлось выпарсивать число о.з.]) сколько включая результат)
- установка монстра (кто поставил, имя монстра, кол-во о.з.)
- заход пользователя (в т.ч. сообщить имя) в MUD
- прекращения сеанса пользователя в MUD (тоже с указанием имени)
- есть и не-широковещательные сообщения, например приветствие от встреченного монстра поступает одному конкретному пользователю
- Прямого взаимодействия между пользователями нет
- Возможны логические гонки: например, два пользователя более-менее одновременно отправили команду атаки на одного и того же монстра, "первый" убил монстра, а второму пришло индивидуальное сообщение о том, что монстра нет. Это терпимо.