class Server(QWidget): def __init__(self, model, prediction, vocabulary): super(Server, self).__init__() self.model = model self.prediction = prediction self.vocabulary = vocabulary self.resize(500, 450) # 1 self.browser = QTextBrowser(self) self.v_layout = QVBoxLayout() self.v_layout.addWidget(self.browser) self.setLayout(self.v_layout) # 2 self.server = QTcpServer(self) if not self.server.listen(QHostAddress.LocalHost, 8080): self.browser.append(self.server.errorString()) self.server.newConnection.connect(self.new_socket_slot) def new_socket_slot(self): sock = self.server.nextPendingConnection() peer_address = sock.peerAddress().toString() peer_port = sock.peerPort() news = 'Connected with address {}, port{}'.format( peer_address, str(peer_port)) self.browser.append(news) sock.readyRead.connect(lambda: self.read_data_slot(sock)) sock.disconnected.connect(lambda: self.disconnected_slot(sock)) # 3 def read_data_slot(self, sock): while sock.bytesAvailable(): datagram = sock.read(sock.bytesAvailable()) message = datagram.decode() answer = self.get_answer(message).encode() sock.write(bytes(answer)) def get_answer(self, message): sentence = pre_dosegment(message) sentence = ' '.join(sentence) prediction1 = self.model.test(str(sentence), self.vocabulary) query = match_question(prediction1, str(message)) answer = self.prediction.run(query, prediction1) return answer # 4 def disconnected_slot(self, sock): peer_address = sock.peerAddress().toString() peer_port = sock.peerPort() news = 'Disconnected with address {}, port {}'.format( peer_address, str(peer_port)) self.browser.append(news) sock.close()
class ReceiverEngine(QObject): newDataPacket = pyqtSignal(str, str) def __init__(self, parent=None, port=NetSettings.nodeDataPort): super().__init__(parent) self.__incomingConnections = dict( ) # QMap<QTcpSocket*, _IncomingConnection> self.__incomingConnectionsAddress = str() self.__incomingConnectionsPort = int() self.__server = None self.__signChecker = SignChecker() self.__serverPort = port def __del__(self): pass # self.stop() @pyqtSlot() def setMaxPendingConnections(self, numConnections: int): if not self.__server: return self.__server.setMapPendingConnections(numConnections) def isListening(self): if not self.__server: return False # SHOULD BE PROTECTED WITH MUTEX return self.__server.isListening() @pyqtSlot(str) def runReceiver(self, hostAddress: str): if not self.__server: self.__server = QTcpServer(self) self.__server.acceptError.connect(self.__error) if not self.__server.listen( QHostAddress(hostAddress), self.__serverPort) and not self.isListening(): print("RECEIVER NOT STARTED", self.__server.errorString()) else: self.__server.newConnection.connect(self.__newConnection) self.__incomingConnectionsAddress = hostAddress self.__incomingConnectionsPort = self.__serverPort print("RECEIVER STARTED") @pyqtSlot() def stop(self): if not self.__server: return if self.isListening(): for socket in self.__incomingConnections.keys(): socket.readyRead.disconnect() socket.disconnected.disconnect() socket.close() self.__incomingConnections.clear() @pyqtSlot() def __newConnection(self): socket = self.__server.nextPendingConnection() print("NEW CONN", socket.peerAddress().toString(), socket.peerPort()) socket.setSocketOption(QAbstractSocket.LowDelayOption, 1) socket.setSocketOption(QAbstractSocket.KeepAliveOption, 0) # socket.setProperty("port", socket.peerPort()) # socket.setProperty("address", socket.peerAddress().toString()) incomingConnection = _IncomingConnection() incomingConnection.socketDescriptor = socket.socketDescriptor() incomingConnection.socket = socket # incomingConnection.socket.setReadBufferSize(1024) incomingConnection.socket.readyRead.connect(self.__readData) incomingConnection.socket.disconnected.connect(self.__disconnected) incomingConnection.buffer = QByteArray() incomingConnection.address = socket.peerAddress().toString() incomingConnection.port = socket.peerPort() self.__incomingConnections[socket] = incomingConnection @pyqtSlot() def __readData(self): socket = self.sender() # print("READ", socket.peerAddress().toString(), socket.peerPort()) # print("read data from", socket.objectName()) incomingConnection = self.__incomingConnections.get(socket, None) if incomingConnection: bytesAvailable = socket.bytesAvailable() # if self.__serverPort != NetSettings.nodeCommandPort: # print(bytesAvailable, "READING FROM SOCKET", socket.peerPort()) if bytesAvailable: incomingConnection.buffer.append(socket.read(bytesAvailable)) while incomingConnection.receivingPacketSize == 0 and incomingConnection.buffer.size() >= 4 \ or incomingConnection.receivingPacketSize > 0 and incomingConnection.buffer.size() >= incomingConnection.receivingPacketSize: if incomingConnection.receivingPacketSize == 0 and incomingConnection.buffer.size( ) >= 4: incomingConnection.receivingPacketSize = self.__bytesToInt( incomingConnection.buffer.left(4)) incomingConnection.buffer.remove(0, 4) if incomingConnection.receivingPacketSize > 0 and incomingConnection.buffer.size( ) >= incomingConnection.receivingPacketSize: packet = bytes( incomingConnection.buffer.left( incomingConnection.receivingPacketSize) ).decode() # if self.__signChecker.checkTran(packet): self.newDataPacket.emit(incomingConnection.address, packet) incomingConnection.buffer.remove( 0, incomingConnection.receivingPacketSize) incomingConnection.receivingPacketSize = 0 else: print("Address disconnected already ") # raise Exception("ERROR WITH ADDRESS") @pyqtSlot() def __disconnected(self): socket = self.sender() print("disconnected from ", socket.objectName()) self.__incomingConnections.pop(socket, None) @pyqtSlot() def __error(self): server = self.sender() print("ERROR", server.errorString()) def __bytesToInt(self, data: QByteArray): temp = int().from_bytes(data, byteorder="little") return temp
class Server(QDialog): FORTUNES = ( "You've been leading a dog's life. Stay off the furniture.", "You've got to think about tomorrow.", "You will be surprised by a loud noise.", "You will feel hungry again in another hour.", "You might have mail.", "You cannot kill time without injuring eternity.", "Computers are not intelligent. They only think they are.") def __init__(self, parent=None): super(Server, self).__init__(parent) self.tcpServer = None self.networkSession = None self.statusLabel = QLabel() quitButton = QPushButton("Quit") quitButton.setAutoDefault(False) manager = QNetworkConfigurationManager() if manager.capabilities() & QNetworkConfigurationManager.NetworkSessionRequired: settings = QSettings(QSettings.UserScope, 'QtProject') settings.beginGroup('QtNetwork') id = settings.value('DefaultNetworkConfiguration', '') settings.endGroup() config = manager.configurationFromIdentifier(id) if config.state() & QNetworkConfiguration.Discovered == 0: config = manager.defaultConfiguration() self.networkSession = QNetworkSession(config, self) self.networkSession.opened.connect(self.sessionOpened) self.statusLabel.setText("Opening network session.") self.networkSession.open() else: self.sessionOpened() quitButton.clicked.connect(self.close) self.tcpServer.newConnection.connect(self.sendFortune) buttonLayout = QHBoxLayout() buttonLayout.addStretch(1) buttonLayout.addWidget(quitButton) buttonLayout.addStretch(1) mainLayout = QVBoxLayout() mainLayout.addWidget(self.statusLabel) mainLayout.addLayout(buttonLayout) self.setLayout(mainLayout) self.setWindowTitle("Fortune Server") def sessionOpened(self): if self.networkSession is not None: config = self.networkSession.configuration() if config.type() == QNetworkConfiguration.UserChoice: id = self.networkSession.sessionProperty('UserChoiceConfiguration') else: id = config.identifier() settings = QSettings(QSettings.UserScope, 'QtProject') settings.beginGroup('QtNetwork') settings.setValue('DefaultNetworkConfiguration', id) settings.endGroup(); self.tcpServer = QTcpServer(self) if not self.tcpServer.listen(): QMessageBox.critical(self, "Fortune Server", "Unable to start the server: %s." % self.tcpServer.errorString()) self.close() return for ipAddress in QNetworkInterface.allAddresses(): if ipAddress != QHostAddress.LocalHost and ipAddress.toIPv4Address() != 0: break else: ipAddress = QHostAddress(QHostAddress.LocalHost) ipAddress = ipAddress.toString() self.statusLabel.setText("The server is running on\n\nIP: %s\nport %d\n\n" "Run the Fortune Client example now." % (ipAddress, self.tcpServer.serverPort())) def sendFortune(self): fortune = self.FORTUNES[random.randint(0, len(self.FORTUNES) - 1)] block = QByteArray() out = QDataStream(block, QIODevice.WriteOnly) out.setVersion(QDataStream.Qt_4_0) out.writeUInt16(0) out.writeQString(fortune) out.device().seek(0) out.writeUInt16(block.size() - 2) clientConnection = self.tcpServer.nextPendingConnection() clientConnection.disconnected.connect(clientConnection.deleteLater) clientConnection.write(block) clientConnection.disconnectFromHost()
class TcpS(QDialog, Ui_TcpServer): """ 文件传输服务器 """ sendFileName = pyqtSignal(str) def __init__(self, parent=None): """ 一些初始设置 """ super(TcpS, self).__init__(parent) self.setupUi(self) self.payloadSize = 64 * 1024 # 读取数据64KB self.totalBytes = 0 # 总大小 self.bytesWritten = 0 # 保存的数据 self.bytesToWrite = 0 # 每次减少连接写的数据量大小 self.theFileName = "" # 文件名(不含路径) self.fileName = "" # 文件全名 self.localFile = QFile() self.outBlock = QByteArray() # QByteArray()的对象,即字节数组 self.time = QTime() self.initServer() def initServer(self): """ 网络设置初始化 """ self.tcpPort = 7788 # 指定了TCP端口为7788 self.tcpServer = QTcpServer(self) self.clientConnection = QTcpSocket(self) # 创建一个Tcp服务器和一个Tcp套接字 self.tcpServer.newConnection.connect(self.sendMessage) # 当有新的连接来的时候发出newConnection信号,我们连接到sendMessage()函数。 self.serverStatuslabel.setText("请选择要传送的文件") self.progressBar.reset() self.serverOpenBtn.setEnabled(True) self.serverSendBtn.setEnabled(False) self.tcpServer.close() # 显示我们开始创建的对话框,打开按钮是可用的,发送按钮是不可用的,进度条复位,先关闭服务器。 def refused(self): """ 对端拒绝接收文件,主程序会调用服务器的refused()函数,关闭服务器。 """ self.tcpServer.close() self.serverStatuslabel.setText("对方拒绝接收") def closeEvent(self, event): """ 关闭事件 """ self.on_serverCloseBtn_clicked() # 产生关闭事件,直接调用关闭窗口按钮函数。 def sendMessage(self): """ 发送文件 """ self.serverSendBtn.setEnabled(False) # 发送按钮不可用 self.clientConnection = self.tcpServer.nextPendingConnection() # self.clientConnection作为连接的QTcpSocket对象返回下一个挂起的连接。 self.clientConnection.bytesWritten.connect(self.updateClientProgress) # 当连接中每次将数据有效载荷写入设备的当前写通道时,都会发出此信号。在此有效负载中写入的数据量为字节数。 self.serverStatuslabel.setText("开始传送文件 {} !".format(self.theFileName)) self.localFile = QFile(self.fileName) if not (self.localFile.open(QFile.ReadOnly)): errorMsg = "无法读取文件 {}:\n {}".format(self.fileName, self.localFile.errorString()) QMessageBox.warning(self, "应用程序", errorMsg) return # 尝试打开文件,要是存在问题就报错。 self.serverCloseBtn.setText("取消") self.totalBytes = self.localFile.size() # 记录一下需要传输的文件大小。单位:字节 sendOut = QDataStream(self.outBlock, QIODevice.WriteOnly) # 这里的self.outBlock是QByteArray()的对象,即字节数组;QIODevice的模式为WriteOnly sendOut.setVersion(QDataStream.Qt_5_4) # 设定QDataStream的版本为Qt_5_4 self.time.start() # 开始计时 currentFile = self.fileName.split("/")[-1] # 传输的文件名 sendOut.writeInt64(0) sendOut.writeInt64(0) sendOut.writeQString(currentFile) self.totalBytes += self.outBlock.size() # 在sendOut中写入文件名以及文件名和文件的大小,大小都是以字节为单位的。 sendOut.device().seek(0) sendOut.writeInt64(self.totalBytes) sendOut.writeInt64(self.outBlock.size() - 2) # QIODevice读写位置移动到0。然后分别写入总的大小和文件名大小。 self.bytesToWrite = self.totalBytes - self.clientConnection.write( self.outBlock) # 待传输文件的大小。 self.outBlock.resize(0) # outBlock清零。 def updateClientProgress(self, numBytes): """ 发送进度显示 """ qApp.processEvents() # 长时间工作用,以免窗口假死 self.bytesWritten += numBytes if self.bytesWritten > 0: self.block = self.localFile.read( min(self.bytesToWrite, self.payloadSize)) self.bytesToWrite -= self.clientConnection.write(self.block) else: self.localFile.close() # 当我们待写入的字节数大于0时,我们每次读取的数据都是小于等于self.payloadSize的,这个self.payloadSize我们定义是64KB。 # self.bytesToWrite每次减少连接写的数据量大小。 # 要是待写入的字节数小于等于0,则关闭文件。 byteSent = self.bytesWritten / (1024 * 1024) # 已经写了多少文件 useTime = self.time.elapsed() / 1000 # 传输用了多长时间 speed = self.bytesWritten / useTime / (1024 * 1024) # 传输速度 total = self.totalBytes / (1024 * 1024) # 总大小 left = (total - byteSent) / speed # 表示剩余时间 if byteSent < 0.01: byteSent = self.bytesWritten / 1024 speed = self.bytesWritten / useTime / 1024 total = self.totalBytes / 1024 if left > 0: sendInfo = "已发送 {0:.2f}KB({1:.2f}KB/s)\n共{2:.2f}KB 已用时:{3:.1f}秒\n 估计剩余时间:{4:.1f}秒".format( byteSent, speed, total, useTime, left) else: sendInfo = "已发送 {0:.2f}KB({1:.2f}KB/s)\n共{2:.2f}KB 用时:{3:.1f}秒\n".format( byteSent, speed, total, useTime) else: if left > 0: sendInfo = "已发送 {0:.2f}MB({1:.2f}MB/s)\n共{2:.2f}MB 已用时:{3:.1f}秒\n 估计剩余时间:{4:.1f}秒".format( byteSent, speed, total, useTime, left) else: sendInfo = "已发送 {0:.2f}MB({1:.2f}MB/s)\n共{2:.2f}MB 用时:{3:.1f}秒\n".format( byteSent, speed, total, useTime) self.progressBar.setMaximum(total) self.progressBar.setValue(byteSent) if self.bytesWritten == self.totalBytes: self.serverCloseBtn.setText("关闭") # 进度条显示的方式,以及当传输的字节数等于总的字节数的时候,按钮就显示关闭。 self.serverStatuslabel.setText(sendInfo) @pyqtSlot() def on_serverOpenBtn_clicked(self): """ 打开文件准备发送 """ self.fileName = QFileDialog.getOpenFileName(self, '打开文件', './')[0] if self.fileName: self.theFileName = self.fileName.split("/")[-1] self.serverStatuslabel.setText("要传送的文件为:{}".format( self.theFileName)) self.serverSendBtn.setEnabled(True) self.serverOpenBtn.setEnabled(False) @pyqtSlot() def on_serverSendBtn_clicked(self): """ 发送文件,等待接收 """ if not (self.tcpServer.listen(QHostAddress.Any, self.tcpPort)): errorMsg = self.tcpServer.errorString() QMessageBox.warning(self, "错误", "发送失败:\n {}".format(errorMsg)) self.TcpServer.close() return self.serverStatuslabel.setText("等待对方接收... ...") self.serverSendBtn.setEnabled(False) self.sendFileName.emit(self.theFileName) @pyqtSlot() def on_serverCloseBtn_clicked(self): """ 取消或者关闭 """ if self.tcpServer.isListening(): self.tcpServer.close() if self.localFile.isOpen(): self.localFile.close() self.clientConnection.abort() if self.serverCloseBtn.text() == "取消": self.serverCloseBtn.setText("关闭") else: self.close() self.serverOpenBtn.setEnabled(True) self.serverSendBtn.setEnabled(False) self.progressBar.reset() self.totalBytes = 0 self.bytesWritten = 0 self.bytesToWrite = 0 self.serverStatuslabel.setText("请选择要传送的文件")
class Server(QWidget): def __init__(self): QWidget.__init__(self) self.serverOpen = False self.tcpServer = None self.tcpServerConnection = None self.textEdit = None self.lineEdit = None self.create_widgets() def create_widgets(self): self.tcpServer = QTcpServer() self.textEdit = QTextEdit() self.textEdit.setReadOnly(True) self.lineEdit = QLineEdit() self.lineEdit.setPlaceholderText("Enter response") self.lineEdit.setMaxLength(50) self.lineEdit.setEnabled(True) vBox = QVBoxLayout() vBox.addWidget(self.textEdit) vBox.addWidget(self.lineEdit) self.setLayout(vBox) self.tcpServer.newConnection.connect(self.accept_connection) def add_message(self, message): self.textEdit.moveCursor(QTextCursor.End) self.textEdit.insertPlainText(message) self.textEdit.moveCursor(QTextCursor.End) def open_server(self): if (len(self.lineEdit.text()) == 0): self.add_message("You must enter a response\n") QMessageBox.critical(self, "Error", "You must enter a response") return False self.tcpServer.listen(QHostAddress(__serverUrl__), 9000) self.serverOpen = self.tcpServer.isListening() if (self.serverOpen): serverAddress = self.tcpServer.serverAddress().toString() serverPort = self.tcpServer.serverPort() self.add_message("Server opened on %s on port %d\n" % (serverAddress, serverPort)) self.lineEdit.setEnabled(False) else: self.add_message(self.tcpServer.errorString()) QMessageBox.critical(self, "Error", self.tcpServer.errorString()) return True def accept_connection(self): self.tcpServerConnection = self.tcpServer.nextPendingConnection() self.tcpServerConnection.readyRead.connect(self.receive_data) self.tcpServerConnection.disconnected.connect(self.socket_disconnected) peerAddress = self.tcpServerConnection.peerAddress().toString() peerPort = self.tcpServerConnection.peerPort() self.add_message("Connected to %s on port %d\n" % (peerAddress, peerPort)) def receive_data(self): rxData = self.tcpServerConnection.readAll() self.add_message("Received '" + rxData.data().decode('utf8') + "'\n") txString = self.lineEdit.text() self.tcpServerConnection.write(txString.encode()) self.add_message("Wrote '" + txString + "'\n") def socket_disconnected(self): self.add_message("Disconnected from client\n") def close_server(self): if (self.serverOpen): self.tcpServer.close() self.lineEdit.setEnabled(True)
class Dialog(QDialog): TotalBytes = 50 * 1024 * 1024 PayloadSize = 65536 def __init__(self, parent=None): super(Dialog, self).__init__(parent) self.tcpServer = QTcpServer() self.tcpClient = QTcpSocket() self.bytesToWrite = 0 self.bytesWritten = 0 self.bytesReceived = 0 self.clientProgressBar = QProgressBar() self.clientStatusLabel = QLabel("Client ready") self.serverProgressBar = QProgressBar() self.serverStatusLabel = QLabel("Server ready") self.startButton = QPushButton("&Start") self.quitButton = QPushButton("&Quit") buttonBox = QDialogButtonBox() buttonBox.addButton(self.startButton, QDialogButtonBox.ActionRole) buttonBox.addButton(self.quitButton, QDialogButtonBox.RejectRole) self.startButton.clicked.connect(self.start) self.quitButton.clicked.connect(self.close) self.tcpServer.newConnection.connect(self.acceptConnection) self.tcpClient.connected.connect(self.startTransfer) self.tcpClient.bytesWritten.connect(self.updateClientProgress) self.tcpClient.error.connect(self.displayError) mainLayout = QVBoxLayout() mainLayout.addWidget(self.clientProgressBar) mainLayout.addWidget(self.clientStatusLabel) mainLayout.addWidget(self.serverProgressBar) mainLayout.addWidget(self.serverStatusLabel) mainLayout.addStretch(1) mainLayout.addSpacing(10) mainLayout.addWidget(buttonBox) self.setLayout(mainLayout) self.setWindowTitle("Loopback") def start(self): self.startButton.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.bytesWritten = 0 self.bytesReceived = 0 while not self.tcpServer.isListening() and not self.tcpServer.listen(): ret = QMessageBox.critical( self, "Loopback", "Unable to start the test: %s." % self.tcpServer.errorString(), QMessageBox.Retry | QMessageBox.Cancel, ) if ret == QMessageBox.Cancel: return self.serverStatusLabel.setText("Listening") self.clientStatusLabel.setText("Connecting") self.tcpClient.connectToHost(QHostAddress(QHostAddress.LocalHost), self.tcpServer.serverPort()) def acceptConnection(self): self.tcpServerConnection = self.tcpServer.nextPendingConnection() self.tcpServerConnection.readyRead.connect(self.updateServerProgress) self.tcpServerConnection.error.connect(self.displayError) self.serverStatusLabel.setText("Accepted connection") self.tcpServer.close() def startTransfer(self): self.bytesToWrite = Dialog.TotalBytes - self.tcpClient.write( QByteArray(Dialog.PayloadSize, "@")) self.clientStatusLabel.setText("Connected") def updateServerProgress(self): self.bytesReceived += self.tcpServerConnection.bytesAvailable() self.tcpServerConnection.readAll() self.serverProgressBar.setMaximum(Dialog.TotalBytes) self.serverProgressBar.setValue(self.bytesReceived) self.serverStatusLabel.setText("Received %dMB" % (self.bytesReceived / (1024 * 1024))) if self.bytesReceived == Dialog.TotalBytes: self.tcpServerConnection.close() self.startButton.setEnabled(True) QApplication.restoreOverrideCursor() def updateClientProgress(self, numBytes): self.bytesWritten += numBytes if self.bytesToWrite > 0: self.bytesToWrite -= self.tcpClient.write( QByteArray(min(self.bytesToWrite, Dialog.PayloadSize), "@")) self.clientProgressBar.setMaximum(Dialog.TotalBytes) self.clientProgressBar.setValue(self.bytesWritten) self.clientStatusLabel.setText("Sent %dMB" % (self.bytesWritten / (1024 * 1024))) def displayError(self, socketError): if socketError == QTcpSocket.RemoteHostClosedError: return QMessageBox.information( self, "Network error", "The following error occured: %s." % self.tcpClient.errorString(), ) self.tcpClient.close() self.tcpServer.close() self.clientProgressBar.reset() self.serverProgressBar.reset() self.clientStatusLabel.setText("Client ready") self.serverStatusLabel.setText("Server ready") self.startButton.setEnabled(True) QApplication.restoreOverrideCursor()
class Server(QDialog): FORTUNES = ("You've been leading a dog's life. Stay off the furniture.", "You've got to think about tomorrow.", "You will be surprised by a loud noise.", "You will feel hungry again in another hour.", "You might have mail.", "You cannot kill time without injuring eternity.", "Computers are not intelligent. They only think they are.") def __init__(self, parent=None): super(Server, self).__init__(parent) self.tcpServer = None self.networkSession = None self.statusLabel = QLabel() quitButton = QPushButton("Quit") quitButton.setAutoDefault(False) manager = QNetworkConfigurationManager() if manager.capabilities( ) & QNetworkConfigurationManager.NetworkSessionRequired: settings = QSettings(QSettings.UserScope, 'QtProject') settings.beginGroup('QtNetwork') id = settings.value('DefaultNetworkConfiguration', '') settings.endGroup() config = manager.configurationFromIdentifier(id) if config.state() & QNetworkConfiguration.Discovered == 0: config = manager.defaultConfiguration() self.networkSession = QNetworkSession(config, self) self.networkSession.opened.connect(self.sessionOpened) self.statusLabel.setText("Opening network session.") self.networkSession.open() else: self.sessionOpened() quitButton.clicked.connect(self.close) self.tcpServer.newConnection.connect(self.sendFortune) buttonLayout = QHBoxLayout() buttonLayout.addStretch(1) buttonLayout.addWidget(quitButton) buttonLayout.addStretch(1) mainLayout = QVBoxLayout() mainLayout.addWidget(self.statusLabel) mainLayout.addLayout(buttonLayout) self.setLayout(mainLayout) self.setWindowTitle("Fortune Server") def sessionOpened(self): if self.networkSession is not None: config = self.networkSession.configuration() if config.type() == QNetworkConfiguration.UserChoice: id = self.networkSession.sessionProperty( 'UserChoiceConfiguration') else: id = config.identifier() settings = QSettings(QSettings.UserScope, 'QtProject') settings.beginGroup('QtNetwork') settings.setValue('DefaultNetworkConfiguration', id) settings.endGroup() self.tcpServer = QTcpServer(self) if not self.tcpServer.listen(): QMessageBox.critical( self, "Fortune Server", "Unable to start the server: %s." % self.tcpServer.errorString()) self.close() return for ipAddress in QNetworkInterface.allAddresses(): if ipAddress != QHostAddress.LocalHost and ipAddress.toIPv4Address( ) != 0: break else: ipAddress = QHostAddress(QHostAddress.LocalHost) ipAddress = ipAddress.toString() self.statusLabel.setText( "The server is running on\n\nIP: %s\nport %d\n\n" "Run the Fortune Client example now." % (ipAddress, self.tcpServer.serverPort())) def sendFortune(self): fortune = self.FORTUNES[random.randint(0, len(self.FORTUNES) - 1)] block = QByteArray() out = QDataStream(block, QIODevice.WriteOnly) out.setVersion(QDataStream.Qt_4_0) out.writeUInt16(0) out.writeQString(fortune) out.device().seek(0) out.writeUInt16(block.size() - 2) clientConnection = self.tcpServer.nextPendingConnection() clientConnection.disconnected.connect(clientConnection.deleteLater) clientConnection.write(block) clientConnection.disconnectFromHost()
class ServerSocket(QObject): """Class defining a socket for the server.""" listening = pyqtSignal(tuple) message_received = pyqtSignal(tuple) client_disconnected = pyqtSignal(str) def __init__(self): """Constructor.""" QObject.__init__(self) self.__tcpServer = QTcpServer() self.__active_sockets = [] self.__tcpServer.newConnection.connect(self.__new_connection) def __new_connection(self): """Method handling a new connection to the server.""" # Connecting the new client client = self.__tcpServer.nextPendingConnection() client.readyRead.connect(self.read_message) client.disconnected.connect(self.__find_disconnected_client) client.disconnected.connect(client.deleteLater) # Not sure self.__active_sockets.append(client) # Hyper important !!! print("A new client connected from address '{}'.".format( client.peerAddress().toString())) def __find_disconnected_client(self): """Method trying to find the disconnected client.""" self.client_disconnected.emit(self.sender().localAddress().toString()) self.__active_sockets = [] for socket in self.__tcpServer.children()[1:]: if int(socket.socketDescriptor()) <= 10000: # Socket is active self.__active_sockets.append(socket) def get_available_ips(self): """Method returning the list of available ips.""" return QNetworkInterface.allAddresses() def listen(self, host=None, port=3000): """Method making the server listening to a given address.""" # If no address was specified: trying to give the best one if host is None: for ip in self.get_available_ips(): if ip != QHostAddress.LocalHost and ip.toIPv4Address(): host = ip if host is None: # No suitable address was found host = QHostAddress.LocalHost # The address was given as string if type(host) == str: host = QHostAddress(host) # For printing... address = "{}:{}".format(host.toString(), port) # Launching server if not self.__tcpServer.listen(host, port): self.__tcpServer.close() print("Unable to listen on address '{}': {}.".format( address, self.__tcpServer.errorString())) raise ConnectionError(self.__tcpServer.errorString()) else: print("Server is listening on address '{}'.".format(address)) self.listening.emit((host, port)) def read_message(self): """Method handling the messages.""" for socket in self.__active_sockets: instr = socket.readAll() message = str(instr, encoding="utf8") if message: self.message_received.emit((message, socket)) def __send_msg(self, message, socket): """Method effectively sending a message.""" socket.write(bytes(message, encoding="utf8")) socket.flush() def send_message(self, message, recipient=None): """Method used to send a message to the clients.""" if recipient: # A single recipient was provided if type(recipient) is not str: # Given socket directly self.__send_msg(message, recipient) else: # Given ip address for socket in self.__active_sockets: if socket.peerAddress().toString() == recipient: self.__send_msg(message, socket) else: # Send for everyone for socket in self.__active_sockets: self.__send_msg(message, socket) # block = QByteArray() # out = QDataStream(block, QIODevice.ReadWrite) # out.setVersion(QDataStream.Qt_5_0) # out.writeUInt16(0) # message = bytes(message, encoding="utf8") # out.writeString(message) # out.device().seek(0) # out.writeUInt16(block.size() - 2) # socket.write(block) def get_address(self): """Method returning the adress.""" return self.__tcpServer.serverAddress() def get_port(self): """Method returning the port.""" return self.__tcpServer.serverPort()
class CodeExecutor: """ This class is responsible for executing code (when starting Tribler in debug mode). The protocol to execute code is as follows. First, a client that wants to execute some code opens a connection with the TCP server and sends the string: <code in base64 format> <task_id>\n This code will be executed and the result will be sent to the client in the following format: result <result> <task_id>\n. If Tribler crashes, the server sends the following result: crash <stack trace in base64 format> Note that the socket uses the newline as separator. """ def __init__(self, port, shell_variables=None): self.logger = logging.getLogger(self.__class__.__name__) self.tcp_server = QTcpServer() self.sockets = [] self.stack_trace = None if not self.tcp_server.listen(port=port): self.logger.error("Unable to start code execution socket! Error: %s", self.tcp_server.errorString()) else: connect(self.tcp_server.newConnection, self._on_new_connection) self.shell = Console(locals=shell_variables or {}, logger=self.logger) def _on_new_connection(self): self.logger.info("CodeExecutor has new connection") while self.tcp_server.hasPendingConnections(): socket = self.tcp_server.nextPendingConnection() connect(socket.readyRead, self._on_socket_read_ready) connect(socket.disconnected, self._on_socket_disconnect(socket)) self.sockets.append(socket) # If Tribler has crashed, notify the other side immediately if self.stack_trace: self.on_crash(self.stack_trace) def run_code(self, code, task_id): self.logger.info(f"Run code for task {task_id}") self.logger.debug(f"Code for execution:\n{code}") try: self.shell.runcode(code) except SystemExit: pass if self.shell.last_traceback: self.on_crash(self.shell.last_traceback) return self.logger.info("Code execution with task %s finished:", task_id) return_value = b64encode(self.shell.locals.get('return_value', '').encode('utf-8')) for socket in self.sockets: socket.write(b"result %s %s\n" % (return_value, task_id)) def on_crash(self, exception_text): self.logger.error(f"Crash in CodeExecutor:\n{exception_text}") self.stack_trace = exception_text for socket in self.sockets: socket.write(b"crash %s\n" % b64encode(exception_text.encode('utf-8'))) def _on_socket_read_ready(self): data = bytes(self.sockets[0].readAll()) parts = data.split(b" ") if len(parts) != 2: return try: code = b64decode(parts[0]).decode('utf8') task_id = parts[1].replace(b'\n', b'') self.run_code(code, task_id) except binascii.Error: self.logger.error("Invalid base64 code string received!") def _on_socket_disconnect(self, socket): def on_socket_disconnect_handler(): self.sockets.remove(socket) return on_socket_disconnect_handler
class TcpS(QDialog, Ui_TcpServer): """ Class documentation goes here. """ sendFileName = pyqtSignal(str) def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(TcpS, self).__init__(parent) self.setupUi(self) self.payloadSize = 64 * 1024 self.totalBytes = 0 self.bytesWritten = 0 self.bytesToWrite = 0 self.theFileName = "" self.fileName = "" self.localFile = QFile() self.outBlock = QByteArray() self.time = QTime() self.initServer() def initServer(self): """ 网络设置初始化 """ self.tcpPort = 7788 self.tcpServer = QTcpServer(self) self.clientConnection = QTcpSocket(self) self.tcpServer.newConnection.connect(self.sendMessage) self.serverStatuslabel.setText("请选择要传送的文件") self.progressBar.reset() self.serverOpenBtn.setEnabled(True) self.serverSendBtn.setEnabled(False) self.tcpServer.close() def refused(self): """ 对端拒绝接收文件 """ self.tcpServer.close() self.serverStatuslabel.setText("对方拒绝接收") def closeEvent(self, event): """ 关闭事件 """ self.on_serverCloseBtn_clicked() def sendMessage(self): """ 发送文件 """ self.serverSendBtn.setEnabled(False) self.clientConnection = self.tcpServer.nextPendingConnection() self.clientConnection.bytesWritten.connect(self.updateClientProgress) self.serverStatuslabel.setText("开始传送文件 {} !".format(self.theFileName)) self.localFile = QFile(self.fileName) if not (self.localFile.open(QFile.ReadOnly)): errorMsg = "无法读取文件 {}:\n {}".format(self.fileName, self.localFile.errorString()) QMessageBox.warning(self, "应用程序", errorMsg) return self.serverCloseBtn.setText("取消") self.totalBytes = self.localFile.size() #单位:字节 sendOut = QDataStream(self.outBlock, QIODevice.WriteOnly) sendOut.setVersion(QDataStream.Qt_5_4) self.time.start() currentFile = self.fileName.split("/")[-1] sendOut.writeInt64(0) sendOut.writeInt64(0) sendOut.writeQString(currentFile) self.totalBytes += self.outBlock.size() sendOut.device().seek(0) sendOut.writeInt64(self.totalBytes) sendOut.writeInt64(self.outBlock.size() - 2) self.bytesToWrite = self.totalBytes - self.clientConnection.write( self.outBlock) self.outBlock.resize(0) def updateClientProgress(self, numBytes): """ 发送进度显示 """ qApp.processEvents() self.bytesWritten += numBytes if self.bytesWritten > 0: self.block = self.localFile.read( min(self.bytesToWrite, self.payloadSize)) self.bytesToWrite -= self.clientConnection.write(self.block) else: self.localFile.close() byteSent = self.bytesWritten / (1024 * 1024) useTime = self.time.elapsed() / 1000 speed = self.bytesWritten / useTime / (1024 * 1024) total = self.totalBytes / (1024 * 1024) left = (total - byteSent) / speed if byteSent < 0.01: byteSent = self.bytesWritten / 1024 speed = self.bytesWritten / useTime / 1024 total = self.totalBytes / 1024 if left > 0: sendInfo = "已发送 {0:.2f}KB({1:.2f}KB/s)\n共{2:.2f}KB 已用时:{3:.1f}秒\n 估计剩余时间:{4:.1f}秒".format( byteSent, speed, total, useTime, left) else: sendInfo = "已发送 {0:.2f}KB({1:.2f}KB/s)\n共{2:.2f}KB 用时:{3:.1f}秒\n".format( byteSent, speed, total, useTime) else: if left > 0: sendInfo = "已发送 {0:.2f}MB({1:.2f}MB/s)\n共{2:.2f}MB 已用时:{3:.1f}秒\n 估计剩余时间:{4:.1f}秒".format( byteSent, speed, total, useTime, left) else: sendInfo = "已发送 {0:.2f}MB({1:.2f}MB/s)\n共{2:.2f}MB 用时:{3:.1f}秒\n".format( byteSent, speed, total, useTime) self.progressBar.setMaximum(total) self.progressBar.setValue(byteSent) if self.bytesWritten == self.totalBytes: self.serverCloseBtn.setText("关闭") self.serverStatuslabel.setText(sendInfo) @pyqtSlot() def on_serverOpenBtn_clicked(self): """ 打开文件 """ self.fileName = QFileDialog.getOpenFileName(self, '打开文件', './')[0] if self.fileName: self.theFileName = self.fileName.split("/")[-1] self.serverStatuslabel.setText("要传送的文件为:{}".format( self.theFileName)) self.serverSendBtn.setEnabled(True) self.serverOpenBtn.setEnabled(False) @pyqtSlot() def on_serverSendBtn_clicked(self): """ 发送文件 """ if not (self.tcpServer.listen(QHostAddress.Any, self.tcpPort)): errorMsg = self.tcpServer.errorString() QMessageBox.warning(self, "错误", "发送失败:\n {}".format(errorMsg)) self.TcpServer.close() return self.serverStatuslabel.setText("等待对方接收... ...") self.serverSendBtn.setEnabled(False) self.sendFileName.emit(self.theFileName) @pyqtSlot() def on_serverCloseBtn_clicked(self): """ 取消或者关闭 """ if self.tcpServer.isListening(): self.tcpServer.close() if self.localFile.isOpen(): self.localFile.close() self.clientConnection.abort() if self.serverCloseBtn.text() == "取消": self.serverCloseBtn.setText("关闭") else: self.close() self.serverOpenBtn.setEnabled(True) self.serverSendBtn.setEnabled(False) self.progressBar.reset() self.totalBytes = 0 self.bytesWritten = 0 self.bytesToWrite = 0 self.serverStatuslabel.setText("请选择要传送的文件")
class TcpServer(QObject): ''' TCP/IP server class. Usage: import sys import tcp from PyQt4.QtCore import QCoreApplication from PyQt4.QtNetwork import QHostAddress def main(): application = QCoreApplication(sys.argv) tcpServer = tcp.TcpServer() def onConnected(descriptor): print("Client [%s] connected. Now total: %s" % (descriptor, len(tcpServer.descriptors()))) tcpServer.write(descriptor, "Hello dude") def onDisconnected(descriptor): print("Client [%s] disconnected. Now total: %s" % (descriptor, len(tcpServer.descriptors()))) def onError(descriptor, error): print("Error [%s]: ", descriptor, error) def onRead(descriptor, data): print("Read from [%s] %s byte(s): %s" % (descriptor, len(data), data)) tcpServer.onConnected = onConnected tcpServer.onDisconnected = onDisconnected tcpServer.onError = onError tcpServer.onRead = onRead tcpServer.listen(QHostAddress.Any, 9000) sys.exit(application.exec_()) if __name__ == "__main__": main() ''' def __init__(self, parent=None): QObject.__init__(self, parent) self.__server = QTcpServer(parent) self.__clients = dict() # All active clients # Callbacks self.__on_connected = None self.__on_disconnected = None self.__on_error = None self.__on_read = None # Signals and slots connections self.__server.newConnection.connect(self.__onNewConnection) # Slots @pyqtSlot() def __onNewConnection(self): ''' The slot is called every time a client connects to the server. The client's socket(QTcpSocket) <socket> and descriptor(int) <descriptor> are defined. The socket is appended to the dictionary of connected clients(key=client's descriptor, value=client's socket). Then, socket's descriptor is passed to __onConnected method. :return: None ''' socket = self.__server.nextPendingConnection() socket.disconnected.connect(self.__onDisconnected) socket.error.connect(self.__onError) socket.readyRead.connect(self.__onReadyRead) descriptor = id(socket) self.__clients[descriptor] = socket self.__onConnected(descriptor) @pyqtSlot() def __onConnected(self, descriptor): ''' The method is called by __onNewConnection every time a client connects to the server. If __on_connected callback is set, it is executed with socket's descriptor(int) <descriptor> argument. :param descriptor(int): a newly connected client's socket descriptor, the socket itself is in self.__clients dictionary(key=client's descriptor, value=client's socket); :return: None ''' if self.__on_connected: self.__on_connected(descriptor) @pyqtSlot() def __onDisconnected(self): ''' The slot is called when the connected client disconnects from the server. The client's socket(QTcpSocket) <socket> and its descriptor(int) <descriptor> are defined, and then the descriptor is passed to __on_disconnected callback. :return: None ''' if self.__on_disconnected: socket = self.sender() descriptor = id(socket) self.__clients.pop(descriptor, None) self.__on_disconnected(descriptor) @pyqtSlot() def __onError(self, socketError): ''' The slot is called when an error(PyQt4.QtNetwork.SocketError) <socketError> occurs. The socket's descriptor(int) <descriptor> with error code(int) <errorCode> and description(str) <errorDescription> are defined and passed to __on_error callback. :param error(QAbstractSocket.SocketError): socket error; :return: None ''' if self.__on_error: socket = self.__server.sender() descriptor = id(socket) errorCode = int(socketError) errorDescription = str(self.__server.errorString()) error = (errorCode, errorDescription) self.__on_error(descriptor, error) @pyqtSlot() def __onReadyRead(self): ''' The slot is called when new data is available for reading from the client. The client's socket descriptor(int) <descriptor> is defined, and all available data(str) <data> is read. Then, the socket descriptor and the data are passed to __on_read callback. :return: None ''' if self.__on_read: socket = self.sender() descriptor = id(socket) data = socket.readAll().data() self.__on_read(descriptor, data) # Setters def __connected(self, callback): self.__on_connected = callback def __disconnected(self, callback): self.__on_disconnected = callback def __error(self, callback): self.__on_error = callback def __read(self, callback): self.__on_read = callback # Methods def isListening(self): ''' Return True if the server is currently listening for incoming connections, otherwise returns False. :return: bool ''' return self.__server.isListening() def listen(self, address=None, port=0): ''' Tell the server to listen for incoming connections on address(QHostAddress) <address> and port(int) <port>. If port is 0, a port is chosen automatically. If address is QHostAddress.Any, the server will listen on all network interfaces. :param address(QHosAddress): address to listen to; :param port(int): the port to listen to; :return: bool, return True on success, otherwise return False ''' self.__server.listen(address, port) def socket(self, descriptor): ''' Return socket(QTcpSocket) with the given descriptor(int) <descriptor> or None if it is not found. :param descriptor(int): socket descriptor; :return: socket(QTcpSocket) or None ''' return self.__clients.get(descriptor, None) def descriptors(self): ''' Return all sockets' descriptors available. :return list of int ''' return sorted(self.__clients.keys()) def write(self, descriptor, data): ''' Write data(str) <data> to the client's socket with the given descriptor(int) <descriptor>. :param descriptor(int): client's socket descriptor; :param data(str), data to be written; :return: int, the number of bytes that were actually written, or -1 if an error occurred ''' socket = self.socket(descriptor) if socket: return socket.write(data) else: return -1 def disconnect(self, descriptor): ''' Disconnect the client socket with the given descriptor(int) <descriptor>. :param descriptor(int): client's socket descriptor; :return: None ''' socket = self.socket(descriptor) if socket: socket.close() def close(self): ''' Close the server. :return: None ''' for socket in self.__clients.values(): socket.close() self.__server.close() # Properties onConnected = property(fset=__connected) onDisconnected = property(fset=__disconnected) onError = property(fset=__error) onRead = property(fset=__read)
class Dialog(QDialog): TotalBytes = 50 * 1024 * 1024 PayloadSize = 65536 def __init__(self, parent=None): super(Dialog, self).__init__(parent) self.tcpServer = QTcpServer() self.tcpClient = QTcpSocket() self.bytesToWrite = 0 self.bytesWritten = 0 self.bytesReceived = 0 self.clientProgressBar = QProgressBar() self.clientStatusLabel = QLabel("Client ready") self.serverProgressBar = QProgressBar() self.serverStatusLabel = QLabel("Server ready") self.startButton = QPushButton("&Start") self.quitButton = QPushButton("&Quit") buttonBox = QDialogButtonBox() buttonBox.addButton(self.startButton, QDialogButtonBox.ActionRole) buttonBox.addButton(self.quitButton, QDialogButtonBox.RejectRole) self.startButton.clicked.connect(self.start) self.quitButton.clicked.connect(self.close) self.tcpServer.newConnection.connect(self.acceptConnection) self.tcpClient.connected.connect(self.startTransfer) self.tcpClient.bytesWritten.connect(self.updateClientProgress) self.tcpClient.error.connect(self.displayError) mainLayout = QVBoxLayout() mainLayout.addWidget(self.clientProgressBar) mainLayout.addWidget(self.clientStatusLabel) mainLayout.addWidget(self.serverProgressBar) mainLayout.addWidget(self.serverStatusLabel) mainLayout.addStretch(1) mainLayout.addSpacing(10) mainLayout.addWidget(buttonBox) self.setLayout(mainLayout) self.setWindowTitle("Loopback") def start(self): self.startButton.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.bytesWritten = 0 self.bytesReceived = 0 while not self.tcpServer.isListening() and not self.tcpServer.listen(): ret = QMessageBox.critical(self, "Loopback", "Unable to start the test: %s." % self.tcpServer.errorString(), QMessageBox.Retry | QMessageBox.Cancel) if ret == QMessageBox.Cancel: return self.serverStatusLabel.setText("Listening") self.clientStatusLabel.setText("Connecting") self.tcpClient.connectToHost(QHostAddress(QHostAddress.LocalHost), self.tcpServer.serverPort()) def acceptConnection(self): self.tcpServerConnection = self.tcpServer.nextPendingConnection() self.tcpServerConnection.readyRead.connect(self.updateServerProgress) self.tcpServerConnection.error.connect(self.displayError) self.serverStatusLabel.setText("Accepted connection") self.tcpServer.close() def startTransfer(self): self.bytesToWrite = Dialog.TotalBytes - self.tcpClient.write(QByteArray(Dialog.PayloadSize, '@')) self.clientStatusLabel.setText("Connected") def updateServerProgress(self): self.bytesReceived += self.tcpServerConnection.bytesAvailable() self.tcpServerConnection.readAll() self.serverProgressBar.setMaximum(Dialog.TotalBytes) self.serverProgressBar.setValue(self.bytesReceived) self.serverStatusLabel.setText("Received %dMB" % (self.bytesReceived / (1024 * 1024))) if self.bytesReceived == Dialog.TotalBytes: self.tcpServerConnection.close() self.startButton.setEnabled(True) QApplication.restoreOverrideCursor() def updateClientProgress(self, numBytes): self.bytesWritten += numBytes if self.bytesToWrite > 0: self.bytesToWrite -= self.tcpClient.write(QByteArray( min(self.bytesToWrite, Dialog.PayloadSize), '@')) self.clientProgressBar.setMaximum(Dialog.TotalBytes) self.clientProgressBar.setValue(self.bytesWritten) self.clientStatusLabel.setText("Sent %dMB" % (self.bytesWritten / (1024 * 1024))) def displayError(self, socketError): if socketError == QTcpSocket.RemoteHostClosedError: return QMessageBox.information(self, "Network error", "The following error occured: %s." % self.tcpClient.errorString()) self.tcpClient.close() self.tcpServer.close() self.clientProgressBar.reset() self.serverProgressBar.reset() self.clientStatusLabel.setText("Client ready") self.serverStatusLabel.setText("Server ready") self.startButton.setEnabled(True) QApplication.restoreOverrideCursor()
class Dialog(QDialog): def __init__(self, parent: QWidget = None) -> None: super().__init__(parent) self.tcpServer = QTcpServer() self.tcpClient = QTcpSocket() self.tcpServerConnection: QTcpSocket = None self.bytesToWrite = 0 self.bytesWritten = 0 self.bytesReceived = 0 self.clientProgressBar = QProgressBar() self.clientStatusLabel = QLabel(self.tr("Client ready")) self.serverProgressBar = QProgressBar() self.serverStatusLabel = QLabel(self.tr("Server ready")) self.startButton = QPushButton(self.tr("&Start")) self.quitButton = QPushButton(self.tr("&Quit")) self.buttonBox = QDialogButtonBox() self.buttonBox.addButton(self.startButton, QDialogButtonBox.ActionRole) self.buttonBox.addButton(self.quitButton, QDialogButtonBox.RejectRole) self.startButton.clicked.connect(self.start) self.quitButton.clicked.connect(self.close) self.tcpServer.newConnection.connect(self.acceptConnection) self.tcpClient.connected.connect(self.startTransfer) self.tcpClient.bytesWritten.connect(self.updateClientProgress) self.tcpClient.error.connect(self.displayError) mainLayout = QVBoxLayout(self) mainLayout.addWidget(self.clientProgressBar) mainLayout.addWidget(self.clientStatusLabel) mainLayout.addWidget(self.serverProgressBar) mainLayout.addWidget(self.serverStatusLabel) mainLayout.addStretch(1) mainLayout.addSpacing(10) mainLayout.addWidget(self.buttonBox) @pyqtSlot() def start(self): self.startButton.setEnabled(False) QGuiApplication.setOverrideCursor(Qt.WaitCursor) self.bytesWritten = 0 self.bytesReceived = 0 while not self.tcpServer.isListening() and not self.tcpServer.listen(): ret = QMessageBox.critical( self, self.tr("Loopback"), self.tr( "Unable to start the test: %s" % (self.tcpServer.errorString()) ), QMessageBox.Retry | QMessageBox.Cancel, ) if ret == QMessageBox.Cancel: return self.serverStatusLabel.setText(self.tr("Listening")) self.clientStatusLabel.setText(self.tr("Connecting")) self.tcpClient.connectToHost( QHostAddress.LocalHost, self.tcpServer.serverPort() ) @pyqtSlot() def acceptConnection(self): self.tcpServerConnection = self.tcpServer.nextPendingConnection() if not self.tcpServerConnection: self.serverStatusLabel.setText( self.tr("Error: got invalid pending connection!") ) return self.tcpServerConnection.readyRead.connect(self.updateServerProgress) self.tcpServerConnection.error.connect(self.displayError) self.tcpServerConnection.disconnected.connect( self.tcpServerConnection.deleteLater ) self.serverStatusLabel.setText(self.tr("Accepted connection")) self.tcpServer.close() @pyqtSlot() def startTransfer(self): # called when the TCP client connected to the loopback server self.bytesToWrite = TOTAL_BYTES - int( self.tcpClient.write(QByteArray(PAYLOAD_SIZE, "@")) ) self.clientStatusLabel.setText(self.tr("Connected")) @pyqtSlot() def updateServerProgress(self): self.bytesReceived += int(self.tcpServerConnection.bytesAvailable()) self.tcpServerConnection.readAll() self.serverProgressBar.setMaximum(TOTAL_BYTES) self.serverProgressBar.setValue(self.bytesReceived) self.serverStatusLabel.setText( self.tr("Received %dMB" % (self.bytesReceived / (1024 * 1024),)) ) if self.bytesReceived == TOTAL_BYTES: self.tcpServerConnection.close() self.startButton.setEnabled(True) QGuiApplication.restoreOverrideCursor() @pyqtSlot("qint64") def updateClientProgress(self, numBytes): self.bytesWritten += int(numBytes) if self.bytesToWrite > 0 and self.tcpClient.bytesToWrite() <= 4 * PAYLOAD_SIZE: self.bytesToWrite -= self.tcpClient.write( QByteArray(min(self.bytesToWrite, PAYLOAD_SIZE), "@") ) self.clientProgressBar.setMaximum(TOTAL_BYTES) self.clientProgressBar.setValue(self.bytesWritten) self.clientStatusLabel.setText( self.tr("Sent %dMB" % (self.bytesWritten / (1024 * 1024),)) ) @pyqtSlot(QAbstractSocket.SocketError) def displayError(self, socketError): if socketError == QTcpSocket.RemoteHostClosedError: return QMessageBox.information( self, self.tr("Network error"), self.tr( "The following error occurred: %s." % (self.tcpClient.errorString(),) ), ) self.tcpClient.close() self.tcpServer.close() self.clientProgressBar.reset() self.serverProgressBar.reset() self.clientStatusLabel.setText(self.tr("Client ready")) self.serverStatusLabel.setText(self.tr("Server ready")) self.startButton.setEnabled(True) QGuiApplication.restoreOverrideCursor()
class CodeExecutor(object): """ This class is responsible for executing code (when starting Tribler in debug mode). The protocol to execute code is as follows. First, a client that wants to execute some code opens a connection with the TCP server and sends the string: <code in base64 format> <task_id>\n This code will be executed and the result will be sent to the client in the following format: result <result> <task_id>\n. If Tribler crashes, the server sends the following result: crash <stack trace in base64 format> Note that the socket uses the newline as separator. """ def __init__(self, port, shell_variables={}): self.logger = logging.getLogger(self.__class__.__name__) self.tcp_server = QTcpServer() self.sockets = [] self.stack_trace = None if not self.tcp_server.listen(port=port): self.logger.error( "Unable to start code execution socket! Error: %s", self.tcp_server.errorString()) else: self.tcp_server.newConnection.connect(self._on_new_connection) self.shell = Console(locals=shell_variables) def _on_new_connection(self): while self.tcp_server.hasPendingConnections(): socket = self.tcp_server.nextPendingConnection() socket.readyRead.connect(self._on_socket_read_ready) socket.disconnected.connect( lambda dc_socket=socket: self._on_socket_disconnect(dc_socket)) self.sockets.append(socket) # If Tribler has crashed, notify the other side immediately if self.stack_trace: self.on_crash(self.stack_trace) def run_code(self, code, task_id): self.shell.runcode(code) stdout = self.shell.stdout.read() stderr = self.shell.stderr.read() self.logger.info("Code execution with task %s finished:", task_id) self.logger.info("Stdout of task %s: %s", task_id, stdout) if 'Traceback' in stderr and 'SystemExit' not in stderr: self.logger.error("Executed code with failure: %s", b64encode(code)) # Determine the return value if 'return_value' not in self.shell.console.locals: return_value = ''.encode('base64') else: return_value = str( self.shell.console.locals['return_value']).encode('base64') for socket in self.sockets: socket.write("result %s %s\n" % (return_value, task_id)) def on_crash(self, exception_text): self.stack_trace = exception_text for socket in self.sockets: socket.write("crash %s\n" % exception_text.encode('base64')) def _on_socket_read_ready(self): data = str(self.sockets[0].readAll()) parts = data.split(" ") if len(parts) != 2: return try: code = parts[0].decode('base64') task_id = parts[1].replace('\n', '') self.run_code(code, task_id) except binascii.Error: self.logger.error("Invalid base64 code string received!") def _on_socket_disconnect(self, socket): self.sockets.remove(socket)
class CodeExecutor(object): """ This class is responsible for executing code (when starting Tribler in debug mode). The protocol to execute code is as follows. First, a client that wants to execute some code opens a connection with the TCP server and sends the string: <code in base64 format> <task_id>\n This code will be executed and the result will be sent to the client in the following format: result <result> <task_id>\n. If Tribler crashes, the server sends the following result: crash <stack trace in base64 format> Note that the socket uses the newline as separator. """ def __init__(self, port, shell_variables={}): self.logger = logging.getLogger(self.__class__.__name__) self.tcp_server = QTcpServer() self.sockets = [] self.stack_trace = None if not self.tcp_server.listen(port=port): self.logger.error("Unable to start code execution socket! Error: %s", self.tcp_server.errorString()) else: self.tcp_server.newConnection.connect(self._on_new_connection) self.shell = Console(locals=shell_variables) def _on_new_connection(self): while self.tcp_server.hasPendingConnections(): socket = self.tcp_server.nextPendingConnection() socket.readyRead.connect(self._on_socket_read_ready) socket.disconnected.connect(lambda dc_socket=socket: self._on_socket_disconnect(dc_socket)) self.sockets.append(socket) # If Tribler has crashed, notify the other side immediately if self.stack_trace: self.on_crash(self.stack_trace) def run_code(self, code, task_id): self.shell.runcode(code) stdout = self.shell.stdout.read() stderr = self.shell.stderr.read() self.logger.info("Code execution with task %s finished:", task_id) self.logger.info("Stdout of task %s: %s", task_id, stdout) if 'Traceback' in stderr and 'SystemExit' not in stderr: self.logger.error("Executed code with failure: %s", b64encode(code)) # Determine the return value if 'return_value' not in self.shell.console.locals: return_value = ''.encode('base64') else: return_value = str(self.shell.console.locals['return_value']).encode('base64') for socket in self.sockets: socket.write("result %s %s\n" % (return_value, task_id)) def on_crash(self, exception_text): self.stack_trace = exception_text for socket in self.sockets: socket.write("crash %s\n" % exception_text.encode('base64')) def _on_socket_read_ready(self): data = str(self.sockets[0].readAll()) parts = data.split(" ") if len(parts) != 2: return try: code = parts[0].decode('base64') task_id = parts[1].replace('\n', '') self.run_code(code, task_id) except binascii.Error: self.logger.error("Invalid base64 code string received!") def _on_socket_disconnect(self, socket): self.sockets.remove(socket)