def start(self): if self.logger_name: self.logger = logging.getLogger(self.logger_name) # noqa else: self.logger = logging.getLogger(self.__class__.__name__) # noqa self.data = {"size_left": 0, "data": b""} # noqa self.tcpSocket = QTcpSocket(self) # noqa self.tcpSocket.setObjectName("qclient_socket") QMetaObject.connectSlotsByName(self) self.tcpSocket.setSocketOption(QAbstractSocket.KeepAliveOption, 1) self.tcpSocket.connectToHost(QHostAddress(self.ip), self.port, QIODevice.ReadWrite) if not self.tcpSocket.waitForConnected(3000): self.failed_to_connect.emit(self.ip, self.port) self.tcpSocket.disconnectFromHost() self.tcpSocket.close() self.logger.error("Failed to connect to {}:{}".format( self.ip, self.port)) return self.close_signal.connect(self.close, Qt.BlockingQueuedConnection) self.write_signal.connect(self._write) self.connect_signal.connect(self._connectTo) self.disconnect_signal.connect(self._disconnect) self.reconnect_signal.connect(self._reconnect)
def __init__(self, *args, **kwargs): super(Client, self).__init__(*args, **kwargs) self.loginWidget = LoginWidget() self.chatWidget = ChatWidget() self.setCentralWidget(self.loginWidget) self.socket = QTcpSocket() self.setupConnections()
def run(self): self.log.debug('Connection id={} is starting'.format(self.conn_id)) def wait_and_read(n_bytes): """ Convenience function that simplifies reading and checking for stop events, etc. Returns a byte string of length n_bytes or None if socket needs to be closed. """ data = b"" while len(data) < n_bytes: if sock.bytesAvailable() == 0: new_data = sock.waitForReadyRead(100) # wait for 100ms between read attempts if not new_data: if sock.state() != sock.ConnectedState or self.need_to_stop(): return None else: continue if self.need_to_stop(): return None new_data = sock.read(n_bytes - len(data)) if type(new_data) != bytes: new_data = new_data.data() data += new_data return data sock = QTcpSocket(None) sock.setSocketDescriptor(self.socketDescriptor) sock.waitForConnected() while True: read_len = wait_and_read(4) if not read_len: break read_len = struct.unpack(">L", read_len)[0] data = wait_and_read(read_len) if not data: break if data.startswith(self.internal_prefix): self.handle_internal_command(data) continue try: logDict = self.deserialize(data) record = LogRecord(logDict) except Exception: self.log.error('Creating log record failed', exc_info=True) continue self.new_record.emit(record) self.log.debug('Connection id={} is stopping'.format(self.conn_id)) sock.disconnectFromHost() sock.close() self.connection_finished.emit(self) self.log.debug('Connection id={} has stopped'.format(self.conn_id))
def on_error(self, conn: QTcpSocket): """Handle socket errors. Args: conn (QTcpSocket): Socket object. Note: Emits error signal. """ device_id = int(conn.objectName()) e = conn.errorString() self.__logger.error("CLIENT-{} Error: {}".format(device_id, e)) self.error.emit(device_id, str(e))
def run(self) -> None: """Run socket manager.""" self._logger = logging.getLogger(self.__class__.__name__) # noqa self.data = {"size_left": 0, "data": b""} # noqa self.socket = QTcpSocket() # noqa self.socket.setParent(None) # noqa self.socket.setSocketOption(QAbstractSocket.KeepAliveOption, 1) if self.socket.setSocketDescriptor(self.socket_descriptor): # noqa self.socket.readyRead.connect(self.on_message) # noqa self.socket.disconnected.connect(self.on_disconnected) # noqa self.socket.error.connect(self.on_error) # noqa self._logger.debug("CLIENT-{} connected to {}:{}".format(self.get_id(), self.socket.peerAddress().toString(), self.socket.peerPort())) self.connected.emit(self.get_id(), self.socket.peerAddress().toString(), self.socket.peerPort()) self.close_signal.connect(self.close, Qt.BlockingQueuedConnection) self.write.connect(self._write)
class Client(QMainWindow): def __init__(self, *args, **kwargs): super(Client, self).__init__(*args, **kwargs) self.loginWidget = LoginWidget() self.chatWidget = ChatWidget() self.setCentralWidget(self.loginWidget) self.socket = QTcpSocket() self.setupConnections() def setupConnections(self): self.loginWidget.ui.pushButton.clicked.connect(self.connectToHost) self.socket.readyRead.connect(self.readData) self.socket.error.connect(self.displayConnectionError) self.chatWidget.ui.pushButton.clicked.connect(self.sendUserMessage) def connectToHost(self): hostAddress = self.loginWidget.ui.addressLineEdit.text() port = int(self.loginWidget.ui.portLineEdit.text()) self.socket.connectToHost(hostAddress, port) if self.socket.waitForConnected(1000): self.nickname = self.loginWidget.ui.nicknameLineEdit.text() self.send(f'login {self.nickname}') self.loginWidget.setParent(None) self.setCentralWidget(self.chatWidget) def send(self, message): self.socket.write(message.encode('utf-8')) def sendUserMessage(self): userMessage = self.chatWidget.ui.lineEdit.text() message = f'say {userMessage}' self.send(message) self.chatWidget.ui.lineEdit.clear() self.chatWidget.ui.lineEdit.setFocus() def readData(self): server = self.sender() data = server.readLine().data().decode('utf-8').split() response = data[0] if response == 'say': self.chatWidget.ui.textBrowser.append(' '.join(data[1:])) def displayConnectionError(self): QMessageBox.information(self, '', 'Could not connect to host') def closeEvent(self, event): self.socket.disconnectFromHost()
class _SocketClient(QObject): """Keeps socket in separate thread. Outgoing signals: - disconnected (device_id: int): Client disconnected. - connected (device_id: int, ip: str, port: int): Client connected. - message (device_id: int, message: bytes): Message from client. - error (device_id: int, error: str): Error occured. - closed (): Closed successfully. Incomming signals: - close_signal (): Emit to close connection. - write (device_id: int, message: bytes): Emit to send message to client with ID in this thread. """ disconnected = Signal(int) connected = Signal(int, str, int) message = Signal(int, bytes) error = Signal(int, str) closed = Signal() close_signal = Signal() write = Signal(bytes) def __init__(self, socket_descriptor, client_id): super(_SocketClient, self).__init__(None) self.socket_descriptor = socket_descriptor self.id = int(client_id) @Slot() def run(self) -> None: """Run socket manager.""" self._logger = logging.getLogger(self.__class__.__name__) # noqa self.data = {"size_left": 0, "data": b""} # noqa self.socket = QTcpSocket() # noqa self.socket.setParent(None) # noqa self.socket.setSocketOption(QAbstractSocket.KeepAliveOption, 1) if self.socket.setSocketDescriptor(self.socket_descriptor): # noqa self.socket.readyRead.connect(self.on_message) # noqa self.socket.disconnected.connect(self.on_disconnected) # noqa self.socket.error.connect(self.on_error) # noqa self._logger.debug("CLIENT-{} connected to {}:{}".format(self.get_id(), self.socket.peerAddress().toString(), self.socket.peerPort())) self.connected.emit(self.get_id(), self.socket.peerAddress().toString(), self.socket.peerPort()) self.close_signal.connect(self.close, Qt.BlockingQueuedConnection) self.write.connect(self._write) @Slot() def get_id(self) -> int: """Get ID of client.""" return self.id @Slot(bytes) def _write(self, message: bytes): """Send task to client. Args: message (bytes): Message to send. """ if self.socket: message = struct.pack('!L', len(message)) + message self.socket.write(message) self.socket.flush() else: self._logger.warning("Socket not created.") @Slot() def on_message(self): """Handle socket messages. Note: Emits message signal. """ while self.socket.bytesAvailable(): size_left = self.data.get("size_left") if size_left > 0: message = self.socket.read(size_left) size_left = size_left - len(message) if size_left > 0: self.data["size_left"] = size_left self.data["data"] += message else: message = self.data.get("data") + message self.data["size_left"] = 0 self.data["data"] = b"" self.message.emit(self.get_id(), message) else: header_size = struct.calcsize('!L') header = self.socket.read(header_size) if len(header) == 4: msg_size = struct.unpack('!L', header)[0] message = self.socket.read(msg_size) if len(message) < msg_size: msg_size = msg_size - len(message) self.data["data"] = message self.data["size_left"] = msg_size else: self.message.emit(self.get_id(), message) @Slot() def on_disconnected(self): """Handle disconnecting socket. Note: Emits disconnected signal. """ if self.socket: try: self._logger.info("CLIENT-{} Disconnected {}: {}:{}".format(self.get_id(), self.socket.peerName(), self.socket.peerAddress().toString(), self.socket.peerPort())) self.socket.close() self.disconnected.emit(self.get_id()) except RuntimeError: pass @Slot() def on_error(self): """Handle socket errors Note: Emits error signal. """ e = self.socket.errorString() self._logger.error("CLIENT-{} Error: {}".format(self.get_id(), e)) self.error.emit(self.get_id(), str(e)) @Slot() def close(self): """Close connection. Note: Emits closed signal. """ self.socket.close() self.socket.deleteLater() self.closed.emit()
def on_connection(self, device_id: int, socket_descriptor: int): """Create new QTcpSocket object and setup connection with client. Args: device_id (int): Socket ID. socket_descriptor (int) Socket descriptor. Note: Emits connected signal. """ socket = QTcpSocket() socket.setParent(None) # noqa if socket.setSocketDescriptor(socket_descriptor): # noqa socket.readyRead.connect(lambda: self.on_message(socket)) # noqa socket.disconnected.connect(lambda: self.on_disconnected(socket)) # noqa socket.error.connect(lambda: self.on_error(socket)) # noqa socket.setObjectName(str(device_id)) self.sockets.append(socket) self.__logger.debug("New connection from CLIENT-{} " "IP: {}:{}".format(socket.objectName(), socket.peerAddress().toString(), socket.peerPort())) self.connected.emit(int(socket.objectName()), socket.peerAddress().toString(), socket.peerPort())
class _SocketClient(QObject): closed = Signal() connected = Signal(str, int) message = Signal(bytes) disconnected = Signal() error = Signal(str) failed_to_connect = Signal(str, int) close_signal = Signal() write_signal = Signal(bytes) reconnect_signal = Signal() connect_signal = Signal(str, int) disconnect_signal = Signal() def __init__(self, ip: str, port: int, loggerName=None): super(_SocketClient, self).__init__(None) self.ip = ip self.port = port self.logger_name = loggerName @Slot() def start(self): if self.logger_name: self.logger = logging.getLogger(self.logger_name) # noqa else: self.logger = logging.getLogger(self.__class__.__name__) # noqa self.data = {"size_left": 0, "data": b""} # noqa self.tcpSocket = QTcpSocket(self) # noqa self.tcpSocket.setObjectName("qclient_socket") QMetaObject.connectSlotsByName(self) self.tcpSocket.setSocketOption(QAbstractSocket.KeepAliveOption, 1) self.tcpSocket.connectToHost(QHostAddress(self.ip), self.port, QIODevice.ReadWrite) if not self.tcpSocket.waitForConnected(3000): self.failed_to_connect.emit(self.ip, self.port) self.tcpSocket.disconnectFromHost() self.tcpSocket.close() self.logger.error("Failed to connect to {}:{}".format( self.ip, self.port)) return self.close_signal.connect(self.close, Qt.BlockingQueuedConnection) self.write_signal.connect(self._write) self.connect_signal.connect(self._connectTo) self.disconnect_signal.connect(self._disconnect) self.reconnect_signal.connect(self._reconnect) @Slot(bytes) def _write(self, message: bytes): """Write dict to server""" message = struct.pack('!L', len(message)) + message self.tcpSocket.write(message) self.tcpSocket.flush() @Slot(int) def on_qclient_socket_error(self, error): self.logger.error(self.tcpSocket.errorString()) self.error.emit(error) @Slot() def on_qclient_socket_connected(self): ip = self.tcpSocket.peerAddress().toString() port = int(self.tcpSocket.peerPort()) self.logger.debug("Connected to {}:{}".format(ip, port)) self.connected.emit(ip, port) @Slot() def on_qclient_socket_disconnected(self): self.logger.info("Disconnected from server") self.disconnected.emit() @Slot() def on_qclient_socket_readyRead(self): while self.tcpSocket.bytesAvailable(): size_left = self.data.get("size_left") if size_left > 0: message = self.tcpSocket.read(size_left) size_left = size_left - len(message) if size_left > 0: self.data["size_left"] = size_left self.data["data"] += message else: message = self.data.get("data") + message self.data["size_left"] = 0 self.data["data"] = b"" self.message.emit(message) else: header_size = struct.calcsize('!L') header = self.tcpSocket.read(header_size) if len(header) == 4: msg_size = struct.unpack('!L', header)[0] message = self.tcpSocket.read(msg_size) if len(message) < msg_size: msg_size = msg_size - len(message) self.data["data"] = message self.data["size_left"] = msg_size else: self.message.emit(message) @Slot(str, int) def _connectTo(self, ip: str, port: int): self._disconnect() self.ip = ip self.port = port self.start() @Slot() def _reconnect(self): self._disconnect() self.start() @Slot() def _disconnect(self): self.tcpSocket.disconnectFromHost() @Slot() def close(self): self._disconnect() self.tcpSocket.close() self.closed.emit()