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
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