Различия между версиями 11 и 12
Версия 11 от 2023-03-21 11:25:42
Размер: 11268
Редактор: FrBrGeorge
Комментарий:
Версия 12 от 2023-03-21 11:37:52
Размер: 11285
Редактор: FrBrGeorge
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 30: Строка 30:
 * {i} Групповая разработка: precious source + committer  * {i} <<Anchor(clone)>>Групповая разработка: precious source + committer

03.20 Ведение совместного проекта

  • {OK} HTTP-сервер для бедных:

    • python3 -m http.server

    • Посмотреть на http://localhost:8000

    • Простой способ узнать IP, если работает DNS:
         1 import socket
         2 socket.gethostbyname(socket.gethostname())
      
    • Если DNS не работает или hostname == "localhost":

         1 import socket
         2 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         3 s.connect(("8.8.8.8", 80))
         4 print(s.getsockname()[0])
         5 s.close()
      
      • Пояснение: .connect() для UDP-сокета настраивает поле адрес_отправителя:порт_отправителя, но собственно соединения не устанавливает. адрес_отправителя при этом определяется маршрутизацией — это IP того интерфейса, через который пойдёт передача.

  • {i} HTTP-сервер, который выводит IP адрес, а не 0.0.0.0

    • Изучить Модуль http.server

      • Подсказка: нужна только функция test()

    • Написать простой http-сервер httpsrv.py порт, который:

      • Принимает единственный параметр — порт
      • При старте вместо http://0.0.0.0:8000/ выводит IP (чтобы поделиться с товарищами)

    • Подсказки:
      • BaseHTTPRequestHandler не достаточно, нужен SimpleHTTPRequestHandler

      • host, port = "0.0.0.0", порт

      • ServerClass.address_family можно не трогать

    • Проверить, работает ли: скачать файл из каталога
  • {i} Групповая разработка: precious source + committer

    • Разбиться на пары
    • В каждой паре, каждому участнику:
      1. Начать «разработку проекта»
        • Сделать пустой precious source репозиторий
        • Настроить репозиторий для публикации:
             1 $ cp .git/hooks/post-update.sample .git/hooks/post-update
             2 $ cat .git/hooks/post-update
             3 
             4 exec git update-server-info
             5 
             6 
          
          • При каждом обновлении репозитория будет запускаться git update-server-info (это нужно для того, чтобы работала публикация с помощью примитивного сервера)

        • Сделать стартовый коммит в него
        • Опубликовать этот репозиторий (порт 8000) с помощью httpsrv.py

          $ cd .git
          $ python3 httpsrv.py 8000
          • Напоминание: сам репозиторий лежит в каталоге .git

      2. Участвовать в разработке другого проекта
        • Склонировать опубликованный precious source репозиторий партнёра:
          $ git clone http://адрес/порт какое-то_название
        • Настроить получившийся committer-репозиторий для публикации (с помощью того же хука post-update)

        • Сделать в нём пару коммитов
        • Сделать в нём аннотированный тег
          $ git tag название_тега -a -m "Аннотация тега"
        • Опубликовать этот репозиторий (порт 8001) с помощью httpsrv.py

      3. Принять запрос на слияние:
        • Добавить опубликованный committer-репозиторий партнёра в качестве ещё одного remote:
             1 $ git remote add committer http://адрес:8001
             2 $ git remote update
             3 
             4  * [new branch]      master        -> committer/master
             5  * [new tag]         название_тега -> название_тега
             6 
          
        • Помержиться с тегом название_тега

          $ git merge название_тега
  • TODO будет ли время? {i} Групповая разработка: merge request в gitlab

  • Разминка перед многопользовательским MUD
    • {OK} Заставляем работать Тупой netcat и Чат сервер из позапрошлой лекции

    • {i} По аналогии с примером командной строки, в которую время от времени спамит второй поток вычислений, написать более удобный клиент к общему чату:

      • В командной строке должны поддерживаться две команды:
        • 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 (тоже с указанием имени)
      • есть и не-широковещательные сообщения, например приветствие от встреченного монстра поступает одному конкретному пользователю
    • Прямого взаимодействия между пользователями нет
    • Возможны логические гонки: например, два пользователя более-менее одновременно отправили команду атаки на одного и того же монстра, "первый" убил монстра, а второму пришло индивидуальное сообщение о том, что монстра нет. Это терпимо.

LecturesCMC/PythonDevelopment2023/Prac/06_SocialProject (последним исправлял пользователь FrBrGeorge 2023-03-21 11:37:52)