Порты и классы витых сокетов

Я работаю над приложением для iPhone для блэкджека, которое взаимодействует с сокетом Twisted, чтобы обеспечить возможность онлайн-игры. Моя проблема на данный момент - найти правильный порт. Позволь мне объяснить.

Я создал класс под названием «Таблица». Он содержит такую ​​информацию, как таблица блэкджека, например, позиции, игроки и колода карт. Одна таблица назначена одному сокету Twisted, а один сокет назначен одному порту. Прямо сейчас тестирую только порты 1025-1034.

Я хочу, чтобы приложение запрашивало количество игроков за каждым столом в порядке возрастания портов. Для тестирования я разрешаю за столом только 1 пользователю. Если 1 пользователь находится за столом, я хочу, чтобы сокет возвращал Table_Not_Found, но вместо этого, даже если пользователь находится за столом, сокет возвращает порт, на котором находится человек, а не следующий порт, на котором никого нет.

Не думаю, что я что-то делаю правильно с классом Table и ищу открытую таблицу. Как мне найти нужный порт? Приложение подключается к порту, если порт занят, возвращается Table_Not_Found, затем приложение запрашивает следующий доступный порт. Но в моем случае сокет всегда возвращает занятый порт. Я могу тестировать только свои iMac и MacBook, поскольку они являются клиентами.

Итог, как мне найти доступную таблицу на порту?

Спасибо!

class Table:
    def __init__(self):
        self.players = []
        self.positions = []
        self.id = 0
        self.numberOfPlayers = 0

    def setID(self, _id):
        self.id = _id

    def setActivePlayer(self, player):
        player.countdown = 20
        while player.count > 0:
            print player.countdown
            time.sleep(1)
            player.countdown -= 1

            if player.countdown == 0:
                print "Out of time"

                moves.surrender(player)


class Socket(Protocol):
    table = Table()

    def connectionMade(self):
        #self.transport.write("""connected""")
        self.factory.clients.append(self)
        print "Clients are ", self.factory.clients

    def connectionLost(self, reason):
        self.factory.clients.remove(self)

    def dataReceived(self, data):
        #print "data is ", data
        a = data.split(':')
        if len(a) > 1:
            command = a[0]
            content = a[1]

            b = content.split(';')
            _UDID = b[0].replace('\n', '')

            if command == "Number_of_Players":
                if Socket.table.numberOfPlayers == 0:
                    msg = "%s:TableFound" % _UDID
                elif Socket.table.numberOfPlayers == 1:
                    msg = "%s:Table_Not_Found" % _UDID

        print msg

        for c in self.factory.clients:
                c.message(msg)

    def message(self, message):
        self.transport.write(message)

NUM_TABLES = 10

factories = [ ]
for i in range(0, NUM_TABLES):
    print i
    factory = Factory()
    factory.protocol = Socket
    factory.clients = []
    factories.append(factory)
    reactor.listenTCP(1025+i, factory)
    #print "Blackjack server started"

reactor.run()

person Alec    schedule 03.06.2012    source источник
comment
Как вы думаете, зачем для этого нужны разные порты? Если все порты должны обеспечивать одинаковую функциональность, вам это не нужно. Вы можете иметь сколько угодно подключений только к одному порту.   -  person ypercubeᵀᴹ    schedule 03.06.2012
comment
Во-вторых, (кто-нибудь поправит меня, если я ошибаюсь), в текущем коде table - это переменная класса, поэтому у вас есть только одна таблица, доступная для всех сокетов, а не по одной на порт.   -  person ypercubeᵀᴹ    schedule 03.06.2012
comment
Если вам нужна одна таблица на сокет, я думаю, что лучше определить table внутри метода Socket.__init__().   -  person ypercubeᵀᴹ    schedule 03.06.2012
comment
Но я действительно считаю, что лучше иметь только один протокол и один порт. Возможно, вам понадобятся некоторые структуры для хранения списка доступных таблиц, подключенных пользователей, стола, за которым они играют, и т. Д. Они могут находиться в центральном объекте (скажем, BlackJackServer).   -  person ypercubeᵀᴹ    schedule 03.06.2012
comment
Тогда, может быть, если бы у меня не было таблицы и поместил бы все ее содержимое в сокет, это могло бы сработать? Для меня это так сложно, я действительно силен в области iPhone, но этот питон сложен. :(   -  person Alec    schedule 03.06.2012


Ответы (1)


Основная проблема, с которой вы столкнулись, - это table = Table() в вашем классе сокета. Это означает, что для всех Socket экземпляров существует только один Table.

Быстрое решение - сохранить каждый Table на Factory, чтобы все соединения с этим Factory (то есть с этим прослушивающим TCP-портом) совместно использовали один Table экземпляр.

Это можно сделать, удалив строку table = Table(), а затем изменив цикл for следующим образом:

for i in range(0, NUM_TABLES):
    print i
    factory = Factory()
    factory.table = Table() # <-- add this line
    factory.protocol = Socket
    factory.clients = []
    factories.append(factory)
    reactor.listenTCP(1025+i, factory)

А затем настройте свой connectionMade таким образом:

def connectionMade(self):
    self.table = self.factory.table

Теперь каждый Socket указывает на свой Factory Table.

Однако с этим кодом есть ряд других серьезных проблем:

  • Вам не нужно и не следует использовать несколько портов для этого протокола. Каждое новое соединение должно появляться и определять, в какую игру в блэкджек оно хочет играть, с сообщением по самому протоколу. Работа с несколькими портами только усложняет людям возможность пройти через брандмауэры, чтобы играть в вашу игру. Вы можете использовать ту же стратегию, просто установив атрибут table в соответствующем экземпляре Socket.

  • Вы ожидаете, что dataReceived будет вызван с целыми сообщениями. Не будет, и это часто задаваемые вопросы, которые вы должны прочитать в документации Twisted . Вернее, это будет во время тестирования, а не во время развертывания в реальном Интернете. Если вы занимаетесь разработкой для iPhone, вам следует использовать Network Link Conditioner для имитации реальных интернет-соединений.

  • Поскольку вы, похоже, не знаете, как работает синтаксический анализ сетевого протокола, вам следует использовать набор для построения протокола, например AMP, чтобы создайте свой проводной протокол. Документация API включает краткое руководство.

  • Вы звоните time.sleep. Это заблокирует весь сервер. Это неправильный способ создания Twisted-сервиса, чувствительного ко времени. Что еще более важно, Twisted не будет обрабатывать ввод, пока он заблокирован, ожидая завершения вашего time.sleep, поэтому каждый игрок всегда немедленно сдастся, вместо того, чтобы иметь возможность разыграть какие-либо карты. Вместо этого следует использовать callLater, чтобы запланировать вызовы, которые меняют состояние игры.

Большинство проблем, с которыми вы сталкиваетесь, - это проблемы с композицией объектов, а не вещи, которые очень специфичны для Twisted или Python. Вам нужно нарисовать для себя карту того, какие экземпляры должны указывать на другие объекты. Важно понимать, что когда вы вызываете реактор, например listenTCP или callLater, вы настраиваете ссылку из реактора на ваш объект. В этом нет ничего волшебного; вы просто говорите «позже вызовите этот метод для этого объекта в этих обстоятельствах». Оттуда все вытекает; ваши сокеты имеют ссылки на ваши таблицы, ваши таблицы имеют ссылки на своих игроков и так далее.

person Glyph    schedule 03.06.2012
comment
Глиф, это был отличный ответ! Вы дали мне проблемы с кодом и т. Д. Единственная проблема в том, что я не могу получить доступ к коду до выходных, когда вернусь к этому компьютеру. Я внесу все коррективы в эти выходные. У меня вопрос: почему бы не использовать порты? Вроде нормально, но я думаю, что это не так. - person Alec; 04.06.2012
comment
@AlecK .: Представьте, что вы хотите, чтобы пользователь переходил от одной таблицы к другой. С вашим дизайном ему придется отключиться и снова подключиться к другому порту, и это (возможно) означает проверку учетных данных на более низком уровне, прохождение межсетевых экранов и все другие вещи, которые необходимо сделать для установления соединения. А что, если за это время места за новым столом будут заняты другими игроками? Вы выгнали игрока с Сервера. - person ypercubeᵀᴹ; 04.06.2012
comment
Сервер автоматически присоединится к столу. Я написал себе библиотеку для iPhone, которая упрощает подключение к серверу. Таблицы имеют неограниченные пределы, нет причин для пользователя менять таблицы. Конечным продуктом не будет мой компьютер, я буду вкладывать средства в другое оборудование. - person Alec; 04.06.2012