Confirmation box on file transfer over sockets using PyQT - python

I have a confirmation box which gets called when sending a file over the network. However, the function for the Signal is in the MainWindow class and uses variables from the Worker thread. But it doesn't work because the variables in the worker thread are not in the right scope.
Any idea how I can pass the msg variable to the saveFile function in the MainWindow class from the signal?
Edit: What I needed to do was pass an argument to my signal but I figured it out. Sorry for the confusion. I was unsure what needed to be done.
Here's a working example:
import socket
import select
import sys, os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
CMD_FILE = 1
CLIENT_PORT = 9001
CLIENT_HOST = '127.0.0.1'
class MainWindow(QWidget):
def __init__(self, parent=None):
#super(QWidget, self).__init__(parent)
super(MainWindow, self).__init__(parent)
self.resize(100, 50)
self.thread = Worker()
self.thread.start()
self.file_button = QPushButton('Send a File')
self.connect(self.file_button, SIGNAL("released()"), self.sendFile)
self.connect_button = QPushButton('Connect To Server')
self.connect(self.connect_button, SIGNAL("released()"), self.connectToServer)
self.connect(self.thread, SIGNAL('triggered(PyQt_PyObject)'), self.saveFile)
self.layout = QFormLayout()
self.layout.addRow(self.file_button, self.connect_button)
self.setLayout(self.layout)
def connectToServer(self):
global s
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((str(CLIENT_HOST).strip(), CLIENT_PORT))
print "Connected to ", str(CLIENT_HOST)
except:
print "unable to connect"
def clientAll(self, cmd, msg):
#check if connnected send a message
s.sendall(cmd + msg)
def sendFile(self):
filename=QFileDialog.getOpenFileName(self, 'Open File', '.')
f = open(filename, 'rb')
myFile = f.read()
self.clientAll(chr(CMD_FILE), myFile)
f.close()
print filename, "Sent\n"
def saveFile(self, msg):
reply = QMessageBox.question(self, 'Message',
"Are you sure you wish to download this file?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
filename = QFileDialog.getSaveFileName(self, 'Save File', '.')
f = open(filename, 'wb')
f.write(msg)
f.close()
print filename, "Recieved"
else:
pass
class Worker(QThread):
def __init__(self):
QThread.__init__(self)
self.exiting = False
def __del__(self):
self.exiting = True
self.wait()
def run(self):
source_ip = ''
#socket.gethostbyname(socket.gethostname())
PORT = 9001
### Initialize socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((source_ip, PORT))
#
server_socket.listen(5)
read_list = [server_socket]
### Start receive loop
while True:
readable, writable, errored = select.select(read_list, [], [])
for s in readable:
if s is server_socket:
conn, addr = s.accept()
read_list.append(conn)
else:
msg = conn.recv(12024)
if msg:
cmd, msg = ord(msg[0]),msg[1:]
if cmd == CMD_FILE:
if not msg: break
self.emit(SIGNAL('triggered(PyQt_PyObject)'), msg)
else:
s.close()
read_list.remove(s)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
win.setWindowTitle('CATS!!! <3')
win.show()
sys.exit(app.exec_())

I think I don't understand exactly your situation.
However, did you try to define a new (custom) signal?
If you define a new signal with pyqtSignal,
you can emit the signal with parameters.
Documentation on signal and slots (new style).

Related

Adapt thread to select in Python

While studying about networks, i found a very common exercise that i thought was pretty insteresting, that is an application to manage simple chatrooms using sockets in Python
The thing is that i found a solution that uses thread, and was wondering how to adapt the solution i found from thread use to select.
The server.py :
from http import client
import os
import socket
import threading
import time
class Server:
def __init__(self, host, port):
self.HOST = host
self.PORT = port
self.rooms_list = []
def get_network(self):
return (self.HOST,self.PORT)
def run(self):
try:
self.create_connection_TCP()
self.accept_connection_rooms()
except:
print("Ocorreu um erro com o servidor principal")
os._exit(1)
def getList(self):
...
def create_connection_TCP(self):
server = (self.HOST, self.PORT)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
self.socket.bind(server)
except:
print("Bind failed")
os._exit(1)
self.socket.listen(100)
def accept_connection_rooms(self):
while True:
try:
client, client_address = self.socket.accept()
thread = threading.Thread(target = self.control_connection, args = (client, ))
thread.start()
except:
print("Failing while creating conection")
os._exit(1)
def check_comand(self, client_socket):
message = client_socket.recv(1024).decode('utf-8')
command = message.split(':')
if command[0] == '/shutdown':
self.socket.close()
if command[0] == '/add_room':
room = ':'.join(command[1:4])
print(room)
if not room in self.rooms_list:
qtd_clients = len(self.rooms_list)
print(f"servidor: {room} | max clients: {command[4]}")
room = ':'.join(command[1:5])
self.rooms_list.append(room)
if command[0] == '/get_room':
index = int(command[1])
try:
room = self.rooms_list[index].split(':')
room = ':'.join(room[1:3])
client_socket.send(f"{room}".encode('utf-8'))
except IndexError:
client_socket.send("error: invald option".encode('utf-8'))
if command[0] == '/get_room_id':
message = len(self.rooms_list)
client_socket.send(message.encode('utf-8'))
if command[0] == '/list_rooms':
rooms = []
for index in range(len(self.rooms_list)):
room_name = self.rooms_list[index].split(':')[0]
rooms.append(f"{index} - {room_name}")
rooms = '\n'.join(rooms)
client_socket.send(f"{rooms}".encode('utf-8'))
# print(f"{rooms}")
if command[0] == '/close_room':
room = ':'.join(command[1:4])
self.rooms_list.remove(room)
print(f"closed_room: {room}")
def control_connection(self, client):
self.check_comand(client)
def close_server(self):
self.socket.close()
server = Server('127.0.0.1', 5000)
server.run()
Probably a good solution is to use select to listen all sockets connections and implement on accept_connection_rooms to manage new sockets

Chatroom app only updates messages when send button is pressed

I've only just started using pyQt6 as of today, as tkinter was giving me some issues, however now that I have the base of the app working, I'm faced with an issue, my chat (self.output) will only update with new messages anytime that the send button is pressed, this of course is not how I would like it to be working, I'd rather it update once a message has been sent from the server, is there any solution to this problem?
Here is the code
from ast import Delete
import socket
import threading
from PyQt6.QtWidgets import *
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import rsa
import sys
app = QApplication(sys.argv)
HOST = '127.0.0.1'
PORT = 9090
shost = '127.0.0.1'
sport = 9090
def loadKeys():
with open('keys/publicKey.pem', 'rb') as p:
publicKey = rsa.PublicKey.load_pkcs1(p.read())
with open('keys/privateKey.pem', 'rb') as p:
privateKey = rsa.PrivateKey.load_pkcs1(p.read())
return privateKey, publicKey
def encrypt(message, key):
return rsa.encrypt(message.encode('utf-8'), key)
def decrypt(ciphertext, key):
try:
return rsa.decrypt(ciphertext, key).decode('utf-8')
except:
return False
def sign(message, key):
return rsa.sign(message.encode('utf-8'), key, 'SHA-1')
def verify(message, signature, key):
try:
return rsa.verify(message.encode('utf-8'), signature, key,) == 'SHA-1'
except:
return False
privateKey, publicKey = loadKeys()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((shost,sport))
gui_done = False
running = True
class Chatroom(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Harmonic")
self.resize(1920,1080)
self.nickname = QInputDialog.getText(self, 'Nickname', 'Enter your nickname:')
layout = QVBoxLayout()
self.setLayout(layout)
QApplication.processEvents()
self.inputField = QLineEdit()
button = QPushButton('&Send')
button.clicked.connect(self.write)
self.output = QTextEdit()
layout.addWidget(self.inputField)
layout.addWidget(button)
layout.addWidget(self.output)
self.Gui_done = True
self.restoremessages()
receive_thread = threading.Thread(target=self.receive)
receive_thread.start()
def restoremessages(self):
with open('chathistory.txt', 'r') as file:
lines = file.readlines()
for line in lines:
self.output.append('{0}'.format(line))
def write(self):
message = (f"{self.nickname}: {self.inputField.text()}\n")
emessage = encrypt(message, publicKey)
sock.send(emessage)
self.inputField.clear()
def stop(self):
running = False
sock.close
sys.exit(app.exec_())
def receive(self):
while running:
try:
message = sock.recv(10000)
dm = decrypt(message,privateKey)
if message == "NICK":
sock.send(self.nickname.encode())
else:
self.output.append('{0}'.format(dm))
QApplication.processEvents
except ConnectionAbortedError:
print("Connection aborted")
sock.close()
break
except:
print("Error")
sock.close()
break
def closeEvent(self,event):
close = QMessageBox.question(self, "QUIT", "Are you sure you want to stop the process?", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if close == QMessageBox.StandardButton.Yes:
event.accept()
self.stop()
else:
event.ignore()
window = Chatroom()
window.show()
app.exec()
There are certain parts of the code that are redundent that I am aware of, same the error with sys.exit(app.exec_()) for some reason the program would not exit without me throwing an error to do so, so this will have to do for now.

Connecting a PyQt5 application to another python program

I have separately developed programs for a pyqt5 app and a client for communicate with a server.
GUI:
from PyQt5 import QtCore, QtWidgets, QtGui
from screen_stack import Ui_MainWindow_screenstack
from screen1 import Ui_Form_screen1
from screen2 import Ui_Form_screen2
from screen3 import Ui_Form_screen3
from client_cli_oop_with_exception_printing import mainProg
import socket
import threading #maybe this won't useful
import sys
import os
class MainApp(QtWidgets.QMainWindow):
def __init__(self):
super(MainApp, self).__init__() #if init was provided with paren=None, then inside this init parent argument can be passed
self.screenstack = Ui_MainWindow_screenstack()
self.screenstack.setupUi(self)
self.screen1 = scr1()
self.screen2 = scr2()
self.screen3 = scr3()
self.screenstack.stackedWidget.addWidget(self.screen1)
self.screenstack.stackedWidget.addWidget(self.screen2)
self.screenstack.stackedWidget.addWidget(self.screen3)
self.screenstack.stackedWidget.setCurrentWidget(self.screen1)
# self.screen1.s1.connect_tcp.clicked.connect(
# lambda: self.screenstack.stackedWidget.setCurrentWidget(self.screen2)
# )
self.screen1.s1.connect_tcp.clicked.connect(self.init_connect_server)
self.screen2.s2.register_name.clicked.connect(
lambda: self.screenstack.stackedWidget.setCurrentWidget(self.screen3)
)
self.sock = None
self.errScr1 = QtWidgets.QMessageBox()
self.errScr1.setWindowTitle('Error')
def init_connect_server(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.sock.connect((self.screen1.s1.tcp_link.text(), int(self.screen1.s1.tcp_port.text())))
self.screenstack.stackedWidget.setCurrentWidget(self.screen2)
except Exception as e:
self.errScr1.setText(str(e))
self.errScr1.exec_()
def start_client_threads(self):
#all the communication threads should start here..
pass
class scr1(QtWidgets.QWidget):
def __init__(self):
super(scr1,self).__init__()
self.s1=Ui_Form_screen1()
self.s1.setupUi(self)
class scr2(QtWidgets.QWidget):
def __init__(self):
super(scr2,self).__init__()
self.s2=Ui_Form_screen2()
self.s2.setupUi(self)
class scr3(QtWidgets.QWidget):
def __init__(self):
super(scr3,self).__init__()
self.s3=Ui_Form_screen3()
self.s3.setupUi(self)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
sw = MainApp()
sw.show()
sys.exit(app.exec_())
Client:
import socket
import threading
import time
import os
class mainProg:
def __init__(self, host, port):
self.is_connection_lost = threading.Event()
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.client.connect((host, port))
except Exception as e:
print(e)
print('Server is not valid...quitting...')
time.sleep(5)
os._exit(0)
self.start_threads()
def recieve(self):
while True:
try:
message = self.client.recv(1024).decode('utf-8')
if message == 'Nickname':
self.client.send(nickname.encode('utf-8'))
elif message == '': #when server gone, we will recieve a lot of empty strings continuously.. we can make the clients shut the python if server gone, but client waiting server to init again will be cooler
self.is_connection_lost.set()
self.client.close()
print('Connection Lost: waiting for the connection,')
while True:
print('waiting...')
time.sleep(3)
if not self.is_connection_lost.is_set():
print('Connection restored!!!')
break
else:
print(message)
#print(type(message))
except Exception as e:
print(e)
print('An error occured!, Not yet connected!')
#client.close()
#is_connection_lost = True
break
def send_messages(self):
while True:
try:
message = f"{nickname}: {input('')}"
self.client.send(message.encode('utf-8'))
except Exception:
pass
def reconnect_server(self):
time.sleep(3)
while True:
if self.is_connection_lost.is_set():
print('Trying to connect!!!!')
time.sleep(3)
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.client.connect((srv,port))
except Exception as e:
print(f'Reconnect failed due to {e}')
continue
if self.client.recv(1024).decode('utf-8') == '':
self.client.close()
pass
else:
self.client.send(nickname.encode('utf-8'))
self.is_connection_lost.clear() #no problem here, it connects to server when server is up again...
def start_threads(self):
t1 = threading.Thread(target=self.recieve)
t2 = threading.Thread(target=self.send_messages)
t3 = threading.Thread(target=self.reconnect_server)
t1.start()
t2.start()
t3.start()
if __name__ == '__main__':
nickname = input('Choose a nickname: ')
srv = '0.tcp.in.ngrok.io'
port = 14112
mainProg(srv, port)
I know that using qthreads I can rewrite the code for client in GUI and make a functional app. But is there a way to connect both classes, so that I can use self.labelMessage.setText(message) instead of print(message) in client. In another way I am asking is there a way to inherit from multiple classes (MainApp and mainProg) so that I can easily connect both codes?

PyGTK: Userlogin Dialog

currently I'm working on a Server-Client Application with python.
The Server-Client is working. My problem is the GUI.
I'm trying to do this with GTK.
Since 2 weeks I'm testing around but the login-screen wont work.
So here are my questions:
How can I create and connect multiple windows in GTK? e.g first login-screen then main_window
How can a Text_Entry-Dialog be created (all in PyGTK)?
[Edit-03.01.2016] Code:
#!/usr/bin/python3
# coding=utf8
import socket
from gi.repository import GObject, Gio, Gtk
class MyApplication(Gtk.Application):
# Main initialization routine
def __init__(self, application_id, flags):
Gtk.Application.__init__(self, application_id=application_id, flags=flags)
self.connect("activate", self.new_window)
#main_Window(self)
def new_window(self, *args):
self. snc =start_Connection_Window(self)
print("going on")
def main_Window(self):
print "Here I'm "
self.connect("activate", self.new_MainWindow)
self.snc.close()
def new_MainWindow(self):
main_Window(self)
print "main_Window started"
class start_Connection_Window(Gtk.Window):
def __init__(self, application):
self.Application = application
# Read GUI from file and retrieve objects from Gtk.Builder
try:
GtkBuilder = Gtk.Builder.new_from_file()#Some Glade file with two windows
GtkBuilder.connect_signals(self)
except GObject.GError:
print("Error reading GUI file")
raise
# Fire up the main window
self.start_Connection_Window = GtkBuilder.get_object("start_Connection")
self.start_Connection_Window.set_application(application)
self.ServerIP_Input = GtkBuilder.get_object("ServerIP-Input")
self.Username_Input = GtkBuilder.get_object("Username_Input")
self.Password_Input = GtkBuilder.get_object("Password_Input")
self.start_Connection_Window.show()
def on_btn_Connect_clicked(self, button):
button.set_sensitive(False)
try:
self.host = str(self.ServerIP_Input.get_text())
self.username = str(self.Username_Input)
self.password = str(self.Password_Input)
self.port=1317
self.clientsocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.clientsocket.connect((self.host, self.port))
self.LENGTH_SIZE = 4
data='ping'
lenght = str(len(data))
self.clientsocket.send(lenght.zfill(4))
print data
self.clientsocket.send(data)
except:
print "Error!"
button.set_sensitive(True)
self.Application.main_Window()
try:
lenght = self.clientsocket.recv(self.LENGTH_SIZE)
data = self.clientsocket.recv(int(lenght))
print data
if(data == str("ok")):
try:
self.Application.main_Window( )
self.close()
except :
print "Here is the mistake"
else:
print "Failed!"
button.set_sensitive(True)
except:
print "Fail!"
#print "Would Start Conn"
def close(self, *args):
self.start_Connection_Window.destroy()
def on_MainWindow_destroy(self, window):
#self.Application.main_Window()
print "Bye"
def on_Window_destroy(self):
print("Bye aus dem destroyten!")
class main_Window(Gtk.Window):
def __init__(self, application):
self.Application = application
# Read GUI from file and retrieve objects from Gtk.Builder
try:
GtkBuilder = Gtk.Builder.new_from_file()#someGladeFile with two Windows
GtkBuilder.connect_signals(self)
except GObject.GError:
print("Error reading GUI file")
raise
# Fire up the main window
self.MainWindow = GtkBuilder.get_object("main_Window")
self.MainWindow.set_application(application)
self.MainWindow.show()
def on_btn_Connect_clicked(self, button):
print "Would Start Conn"
def close(self, *args):
self.MainWindow.destroy()
def on_MainWindow_destroy(self, window):
#self.Application.new_window()
print "Bye"
def on_Window_destroy(self, window):
#self.Application.new_window()
print "Bye"
def start(self, socket, host, username, password):
self.SClient = SC(host, username, password, self)
self.MainWindow.show()
# Starter
def main():
# Initialize GTK Application
Application = MyApplication("App", Gio.ApplicationFlags.FLAGS_NONE)
print "starting"
# Start GUI
Application.run()
if __name__ == "__main__": main()

Python UDP Socket Not Receiving Data

I am attempting to write a UDP chat system, but for some reason the listen() loop is not working and I can not figure out why.
import socket
import json
import landerdb
import threading
class PeerChat:
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.db = landerdb.Connect("nodes")
self.brok_ip = ""
self.brok_port = 5000
def listen(self):
while True:
msg = self.sock.recv(1024)
print msg
def main(self):
while True:
msg = raw_input("> ")
for x in self.db.find("nodes", "all"):
self.sock.sendto(msg, tuple(x['addr']))
def GetNodes(self):
self.sock.sendto("as", (self.brok_ip, self.brok_port))
with open("nodes", 'wb') as file:
msg, addr = self.sock.recvfrom(1024)
print msg
file.write(msg)
if __name__ == "__main__":
PeerChat().GetNodes()
threading.Thread(target=PeerChat().listen).start()
PeerChat().main()

Categories