Yourmind
@Yourmind
пишу говнокод в перерывах между едой и сериалами

Взаимодействие двух хостов в сетевой игре?

Я пишу серверную часть игры шашки.
Имеются 2 клиента. Каждый клиент может начать кнопку новой игры, выхода или продолжить ходить. Если он ходит, то тут проверяется очередность: белые или черные ходят. А нажать кнопку новой игры или закрытия может любой из них и вегда. И вот я не понимаю: как сделать так, чтобы сигнал и от одного и от другого мы могли "слышать" сразу а не по очереди?

import pickle
import socket

what_colour_now='white'
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(2)
#принимаем соединения для двух хостов
conn1, addr1 = sock.accept()
conn2, addr2 = sock.accept()

while True:
#то что прислал один из игроков
#и вот тут проблема! как сделать так чтобы мы вне зависимости от порядка их могли реагировать на кнопки новой игры и закрытия. просто если я напишу как тут то мы сперва ждем что скажет первый хост а потом реагируем на второй. а если к примеру первый будет что то там долго думать то что второй просто не сможет нам ничего отправить. А если он хотел начать новую игру или выйти? тоесть как сделать так чтобы на эти 2 события мы реагировали сразу?
data1 = conn1.recv(1024)
data2 = conn2.recv(1024)

if not data:
break

f=pickle.loads(data)

conn2.close()
conn1.close()
  • Вопрос задан
  • 169 просмотров
Пригласить эксперта
Ответы на вопрос 2
@Kapustlo
Доброго времени суток, в принципе 66demon666 правильно мыслил, но, к сожалению, не рассказал про практическую сторону. Я предлагаю вам воспользоваться более высокоуровневым стандартным модулем Python "socketserver", который позволяет проще реализовать сервера, которые работают по протоколам UDP и TCP. И так, говоря о настройке сервера, то нам понадобится изначально создать обработчик запросов, класс, который будет наследовать от класса "socketserver.BaseRequestHandler". В нашем новосозданном классе мы должны переопределить метод "handle", который по умолчанию ничего не делает, чтобы мы могли обрабатывать приходящие запросы. Далее мы создаём класс нашего сервера со множественным наследованием, в котором на данном этапе мы не добавим своих методов и не переопределим имеющиеся. Далее я уже пойду немного глубже и расскажу немного про своё мнение об организации игрового процесса. Я предлагаю пока что создать два класса: "Player" и "Session". "Session" будет наследовать наш TCP сервер и в своём "__init__" методе будет присваивать обработчику событий себя, чтобы мы из него могли спокойно оперировать данными сессии. Собственно, класс "Player" был добавлен с целью упрощения работы с данными игроков, дабы не создавать словари с их данными и прочее. В принципе, полагаю, на этом мои разъяснения закончены, остальное вы увидите в коде.

import socket
import threading
import socketserver

class Player:
    def __init__(self, id, name):
        self.id = id
        self.name = name

class TCPRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        encoding = "utf-8"

        data = self.request.recv(1024)

        # Дальше мы обрабатываем данные, которые пришли и, например, создаём из них словарь
        if len(session.get_players()) < 2:
            player = Player(data["id"], data["name"])
            session.add_player(player)
            self.request.send("Some response".encode(encoding))
        else:
            self.request.send("Some error data".encode(encoding))

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

class Session(ThreadedTCPServer):
    def __init__(self, connection_data, request_handler):
        super().__init__(connection_data, request_handler)

        self.max_players = 2
        self.players = {}
        self.over = False

        request_handler.session = self

    def get_players(self):
        return self.players

    def add_player(self, player):
        if type(player) == Player:
            if len(self.players) < self.max_players:
                self.players[player.id] = player
            else:
                raise Exception("Players overflow")
        else:
            raise TypeError("'player' argument must be a 'Player' type")

    def game_over(self):
        self.over = True

if __name__ == "__main__":
    HOST, PORT = "localhost", 80

    session = Session((HOST, PORT), TCPRequestHandler)

    with session:
        session_thread = threading.Thread(target=session.serve_forever)

        session_thread.daemon = True
        session_thread.start()

        while not session.over:
            pass # Заглушка, чтобы сервер работал

        session.shutdown()
Ответ написан
@66demon666
Ну так а как-же, все в одном потоке делается, пока не завершиться одна операция, другая не начнётся. Искать способ разбить на 2 потока,

Но я если честно сделал бы по-другому. Есть одна ф-ция, которая слушает любые запросы от любых клиентов, а в качестве параметров принимает идентификатор клиента (чтобы отличать одного от другого) и собственно параметры того, что мы хотим сделать. Например
Function listen(action, parameters)
If action=="new game"
...
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы