diff options
Diffstat (limited to 'examples/network/loopback/dialog.py')
-rw-r--r-- | examples/network/loopback/dialog.py | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/examples/network/loopback/dialog.py b/examples/network/loopback/dialog.py new file mode 100644 index 000000000..673afce28 --- /dev/null +++ b/examples/network/loopback/dialog.py @@ -0,0 +1,151 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +from PySide6.QtCore import QByteArray, Qt +from PySide6.QtGui import QGuiApplication +from PySide6.QtNetwork import (QAbstractSocket, QHostAddress, QTcpServer, + QTcpSocket) +from PySide6.QtWidgets import (QDialog, QDialogButtonBox, QLabel, QMessageBox, + QProgressBar, QPushButton, QVBoxLayout) + + +class Dialog(QDialog): + def __init__(self, parent=None): + super().__init__(parent) + + self.total_bytes = 50 * 1024 * 1024 # 50 MB + self.payload_size = 64 * 1024 # 64 KB + + self.bytes_to_write = 0 + self.bytes_written = 0 + self.bytes_received = 0 + + self.client_progress_bar = QProgressBar() + self.client_status_label = QLabel("Client ready") + self.server_progress_bar = QProgressBar() + self.server_status_label = QLabel("Server ready") + + self.start_button = QPushButton("&Start") + self.quit_button = QPushButton("&Quit") + + self.button_box = QDialogButtonBox() + self.button_box.addButton(self.start_button, QDialogButtonBox.ActionRole) + self.button_box.addButton(self.quit_button, QDialogButtonBox.RejectRole) + + self.start_button.clicked.connect(self.start) + self.quit_button.clicked.connect(self.close) + + self.tcp_server = QTcpServer() + self.tcp_client = QTcpSocket() + self.tcp_server.newConnection.connect(self.accept_connection) + self.tcp_client.connected.connect(self.start_transfer) + self.tcp_client.bytesWritten.connect(self.update_client_progress) + self.tcp_client.errorOccurred.connect(self.display_error) + + main_layout = QVBoxLayout() + main_layout.addWidget(self.client_progress_bar) + main_layout.addWidget(self.client_status_label) + main_layout.addWidget(self.server_progress_bar) + main_layout.addWidget(self.server_status_label) + main_layout.addStretch(1) + main_layout.addSpacing(10) + main_layout.addWidget(self.button_box) + self.setLayout(main_layout) + + self.setWindowTitle("Loopback") + + def start(self): + + self.start_button.setEnabled(False) + + QGuiApplication.setOverrideCursor(Qt.WaitCursor) + + self.bytes_written = 0 + self.bytes_received = 0 + + while not self.tcp_server.isListening() and not self.tcp_server.listen(): + ret: QMessageBox.StandardButton = QMessageBox.critical( + self, + "Loopback", + f"Unable to start the test {self.tcp_server.errorString()}", + QMessageBox.Retry | QMessageBox.Cancel, + ) + if ret == QMessageBox.Cancel: + return + + self.server_status_label.setText("Listening") + self.client_status_label.setText("Connecting") + self.tcp_client.connectToHost(QHostAddress.LocalHost, self.tcp_server.serverPort()) + + def accept_connection(self): + + self.tcp_server_connection = self.tcp_server.nextPendingConnection() + if not self.tcp_server_connection: + self.server_status_label.setText("Error: got invalid pending connection") + return + + self.tcp_server_connection.readyRead.connect(self.update_server_progress) + self.tcp_server_connection.errorOccurred.connect(self.display_error) + self.tcp_server_connection.disconnected.connect(self.tcp_server_connection.deleteLater) + + self.server_status_label.setText("Accepted connection") + self.tcp_server.close() + + def start_transfer(self): + + # Called when the TCP client has connected to the loopback server + self.bytes_to_write = self.total_bytes - self.tcp_client.write( + QByteArray(self.payload_size, "@") + ) + self.client_status_label.setText("Connected") + + def update_server_progress(self): + + self.bytes_received += self.tcp_server_connection.bytesAvailable() + self.tcp_server_connection.readAll() + + self.server_progress_bar.setMaximum(self.total_bytes) + self.server_progress_bar.setValue(self.bytes_received) + self.server_status_label.setText(f"Received {self.bytes_received / (1024 ** 2)} MB") + + if self.bytes_received == self.total_bytes: + + self.tcp_server_connection.close() + self.start_button.setEnabled(True) + + QGuiApplication.restoreOverrideCursor() + + def update_client_progress(self, num_bytes: int): + + # called when the TCP client has written some bytes + self.bytes_written += num_bytes + + # only write more if not finished and when the Qt write buffer is below a certain size + if self.bytes_to_write > 0 and self.tcp_client.bytesToWrite() <= 4 * self.payload_size: + self.bytes_to_write -= self.tcp_client.write( + QByteArray(min(self.bytes_to_write, self.payload_size), "@") + ) + + self.client_progress_bar.setMaximum(self.total_bytes) + self.client_progress_bar.setValue(self.bytes_written) + self.client_status_label.setText(f"Sent {self.bytes_written / (1024 ** 2)} MB") + + def display_error(self, socket_error: QAbstractSocket.SocketError): + if socket_error == QAbstractSocket.RemoteHostClosedError: + return + + QMessageBox.information( + self, + "Network error", + f"The following error occurred: {self.tcp_client.errorString()}", + ) + + self.tcp_client.close() + self.tcp_server.close() + self.client_progress_bar.reset() + self.server_progress_bar.reset() + self.client_status_label.setText("Client ready") + self.server_status_label.setText("Server ready") + self.start_button.setEnabled(True) + + QGuiApplication.restoreOverrideCursor() |