示例#1
0
class NetClient:
    """
    Main networking class.
    """
    def __init__(self, server_address):
        # server information
        self.server_address = server_address
        self.server_port = 15000
        self.timeout = 4000
        self.server_connection = None

        # networking modules from panda3d
        self.manager = QueuedConnectionManager()
        self.reader = QueuedConnectionReader(self.manager, 0)
        self.writer = ConnectionWriter(self.manager, 0)

        # modules that deal with messages
        self.sender_manager = MessageSendersManager(self)
        self.handler = Handler(self)
        self.section_state_fetcher = SectionStateFetcher(self)

    def connect(self):
        """
        Establish connection with the server.
        """
        self.server_connection = self.manager.open_TCP_client_connection(
            self.server_address, self.server_port, self.timeout)
        if self.server_connection:
            self.reader.add_connection(self.server_connection)
            return True
        return False

    def send_ready_for_updates(self):
        """
        Send message to the server saying that client is ready for updates about game state.
        """
        datagram = PyDatagram()
        ReadyForSyncRequest.build().dump(datagram)
        self.writer.send(datagram, self.server_connection)

    def begin_sync_with_server(self):
        """
        Start synchronizing client's state with server's state.
        """
        core.instance.task_mgr.add(self.listen_for_updates,
                                   "listen-for-updates")

    def listen_for_updates(self, task):
        """
        Listen for any incoming packets from the server.
        """
        if self.reader.data_available():
            datagram = NetDatagram()
            if self.reader.get_data(datagram):
                self.handler.handle_data(datagram)
        return Task.cont
示例#2
0
class NetworkConnector(NetworkManager):
    notify = directNotify.newCategory('NetworkConnector')

    def __init__(self, dc_loader, address, port, channel, timeout=5000):
        NetworkManager.__init__(self)

        self._dc_loader = dc_loader
        self.__address = address
        self.__port = port
        self._channel = channel
        self.__timeout = timeout

        self.__manager = QueuedConnectionManager()
        self.__reader = QueuedConnectionReader(self.__manager, 0)
        self.__writer = ConnectionWriter(self.__manager, 0)

        self.__socket = None

        self.__read_task = None
        self.__disconnect_task = None

    @property
    def dc_loader(self):
        return self._dc_loader

    @property
    def channel(self):
        return self._channel

    @channel.setter
    def channel(self, channel):
        self._channel = channel

    def setup(self):
        if not self.__socket:
            self.__socket = self.__manager.open_TCP_client_connection(
                self.__address, self.__port, self.__timeout)

            if not self.__socket:
                raise NetworkError(
                    'Failed to connect TCP socket on address: <%s:%d>!' %
                    (self.__address, self.__port))

            self.__reader.add_connection(self.__socket)
            self.register_for_channel(self._channel)

        self.__read_task = task_mgr.add(self.__read_incoming,
                                        self.get_unique_name('read-incoming'),
                                        taskChain=task_chain)

        self.__disconnect_task = task_mgr.add(
            self.__listen_disconnect,
            self.get_unique_name('listen-disconnect'),
            taskChain=task_chain)

    def register_for_channel(self, channel):
        """
        Registers our connections channel with the MessageDirector
        """

        datagram = NetworkDatagram()
        datagram.add_control_header(channel, types.CONTROL_SET_CHANNEL)
        self.handle_send_connection_datagram(datagram)

    def unregister_for_channel(self, channel):
        """
        Unregisters our connections channel from the MessageDirector
        """

        datagram = NetworkDatagram()
        datagram.add_control_header(channel, types.CONTROL_REMOVE_CHANNEL)
        self.handle_send_connection_datagram(datagram)

    def __read_incoming(self, task):
        """
        Polls for incoming data
        """

        if self.__reader.data_available():
            datagram = NetworkDatagram()

            if self.__reader.get_data(datagram):
                self.__handle_data(datagram)

        return task.cont

    def __listen_disconnect(self, task):
        """
        Watches our connected socket object and determines if the stream has ended..
        """

        if not self.__reader.is_connection_ok(self.__socket):
            self.handle_disconnected()
            return task.done

        return task.cont

    def __handle_data(self, datagram):
        """
        Handles incoming data from the connector
        """

        if not datagram.get_length():
            return

        di = NetworkDatagramIterator(datagram)
        code = di.get_uint8()

        self.handle_datagram(di.get_uint64(), di.get_uint64(), di.get_uint16(),
                             di)

    def handle_send_connection_datagram(self, datagram):
        """
        Sends a datagram to our connection
        """

        self.__writer.send(datagram, self.__socket)

    def handle_datagram(self, channel, sender, message_type, di):
        """
        Handles a datagram that was pulled from the queue
        """

    def handle_disconnect(self):
        """
        Disconnects our client socket instance
        """

        self.__manager.close_connection(self.__socket)

    def handle_disconnected(self):
        """
        Handles disconnection when the socket connection closes
        """

        self.unregister_for_channel(self._channel)
        self.__reader.remove_connection(self.__socket)

    def shutdown(self):
        if self.__read_task:
            task_mgr.remove(self.__read_task)

        if self.__disconnect_task:
            task_mgr.remove(self.__disconnect_task)

        self.__read_task = None
        self.__disconnect_task = None