Issues in Chat App for Local Network - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Networking (https://python-forum.io/forum-12.html) +--- Thread: Issues in Chat App for Local Network (/thread-19852.html) |
Issues in Chat App for Local Network - iMuny - Jul-17-2019 Dear All I hope everyone is doing well. Below is the code for a rudimentary chat app. The server side seems to be working fine but the client side is unable to send messages to the server size and instead just double prints the message. It's not complete and 'Will' contain a lot of bad coding but I'm learning a lot of new stuff day by day this way. from PyQt5 import QtWidgets import sys import socket import threading import ipaddress class MainWindow(QtWidgets.QWidget): def __init__(self): super(MainWindow, self).__init__() self.service = "" self.server = socket.socket() self.client = socket.socket() self.machineIP = socket.gethostbyname(socket.gethostname()) self.isconnected = "" self.connectedusers = [] self.chatwindow = QtWidgets.QListWidget() self.userwindow = QtWidgets.QListWidget() self.typingfield = QtWidgets.QLineEdit() self.sendbutton = QtWidgets.QPushButton("Send") self.sendbutton.clicked.connect(self.sendpressed) self.setupUI() self.show() def setupUI(self): mainlayout = QtWidgets.QVBoxLayout() displaybox = QtWidgets.QHBoxLayout() userlist = QtWidgets.QVBoxLayout() userlist.addWidget(QtWidgets.QLabel("Users Connected:")) userlist.addWidget(self.userwindow) displaybox.addWidget(self.chatwindow, 3) displaybox.addLayout(userlist, 1) inputbox = QtWidgets.QHBoxLayout() inputbox.addWidget(self.typingfield) inputbox.addWidget(self.sendbutton) mainlayout.addLayout(displaybox) mainlayout.addLayout(inputbox) self.setLayout(mainlayout) self.chatwindow.addItem("/host to setup server on local host (Port 7000)") self.chatwindow.addItem("/[email protected] to connect to server on local host (Port 7000)") self.typingfield.setFocus() self.setWindowTitle("TAG CHAT") def sendpressed(self): typedtext = self.typingfield.text() if typedtext: if typedtext[0] == "/": self.metaprocessor(typedtext) else: if self.service: message = self.machineIP + " : " + str(typedtext) self.chatwindow.addItem(message) if self.service == "server": self.broadcast(typedtext) elif self.service == "client": self.server.send(message.encode()) else: self.chatwindow.addItem("Not connected to any group.") self.typingfield.clear() self.typingfield.setFocus() def metaprocessor(self, typedtext): if typedtext == "/host": serverstart = threading.Thread(target=self.makeserver, args=()) serverstart.daemon = True serverstart.start() elif typedtext[0:9] == "/connect@" and len(typedtext) > 9: userip = typedtext[9:] try: ipaddress.ip_address(userip) clientstart = threading.Thread(target=self.startclient, args=(userip, 7000)) clientstart.daemon = True clientstart.start() except ValueError: self.chatwindow.addItem("Invalid IP address provided '" + userip + "'") else: self.chatwindow.addItem("Invalid syntax") def startclient(self, serverip, port): self.server.connect((str(serverip), port)) self.service = "client" while True: message = self.server.recv(1024) self.chatwindow.addItem(message.decode()) def makeserver(self): self.chatwindow.addItem("Creating server @ " + self.machineIP + ":7000") self.server.bind((self.machineIP, 7000)) self.chatwindow.addItem("Server started successfully...\nListening to all connections") self.service = "server" self.server.listen(100) while True: conn, addr = self.server.accept() message = "Connected to " + self.machineIP + ":7000" conn.send(message.encode()) self.connectedusers.append((conn, addr)) newconnection = threading.Thread(target=self.startconnection, args=(conn, addr)) newconnection.daemon = True newconnection.start() def startconnection(self, conn, addr): self.chatwindow.addItem("User " + str(addr) + " has joined the group.") while True: data = conn.recv(1024) message = addr[0] + " : " + data.decode() self.broadcast(message) def broadcast(self, typedtext): for each in self.connectedusers: message = each[1][0] + " : " + str(typedtext) each[0].send(message.encode()) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) mainApplication = MainWindow() sys.exit(app.exec_())You'll need to run two instances of the script i guess. To hoset use '/host' to connect to a host use '/connect@[ip address of host]'. Port is set to default 7000. Any help will be highly appreciated. Regards iMu RE: Issues in Chat App for Local Network - micseydel - Jul-19-2019 I'd be interested in helping if you can reproduce the problem with fewer lines of code (I'm thinking 10-20 tops) and only necessary imports. RE: Issues in Chat App for Local Network - iMuny - Aug-19-2019 (Jul-19-2019, 04:11 AM)micseydel Wrote: I'd be interested in helping if you can reproduce the problem with fewer lines of code (I'm thinking 10-20 tops) and only necessary imports. Ahh, I'm really sorry, i forgot to check back after no one replied initially. Anyways I found the problem myself, i.e. human errors, while reviewing. I took the project a little further with some more features then abandoned it after i got bored and started new projects @.@ The final (at the time) code is as below for anyone interested. from PyQt5 import QtWidgets import sys import socket import threading import ipaddress import time import pickle class MainWindow(QtWidgets.QWidget): def __init__(self): super(MainWindow, self).__init__() self.service = "" self.server = socket.socket() self.client = socket.socket() self.machineIP = socket.gethostbyname(socket.gethostname()) self.isconnected = "" self.connectedusers = [] self.unreadcount = 0 self.oldtime = time.time() self.chatwindow = QtWidgets.QListWidget() self.userwindow = QtWidgets.QListWidget() self.typingfield = QtWidgets.QLineEdit() self.typingfield.returnPressed.connect(self.sendpressed) self.sendbutton = QtWidgets.QPushButton("Send") self.sendbutton.clicked.connect(self.sendpressed) self.tray_icon = QtWidgets.QSystemTrayIcon(self) self.tray_icon.activated.connect(self.onTrayIconActivated) self.tray_icon.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_ComputerIcon)) show_action = QtWidgets.QAction("Show", self) quit_action = QtWidgets.QAction("Exit", self) show_action.triggered.connect(self.show) quit_action.triggered.connect(self.shutdownapp) tray_menu = QtWidgets.QMenu() tray_menu.addAction(show_action) tray_menu.addAction(quit_action) self.tray_icon.setContextMenu(tray_menu) self.tray_icon.show() self.setupUI() self.show() def closeEvent(self, event): if self.service == "server": event.ignore() self.hide() self.tray_icon.showMessage( "TAG IM", "App Minimized (Running as Host)", QtWidgets.QSystemTrayIcon.Information, 1000) elif self.service == "client": event.ignore() self.hide() self.tray_icon.showMessage( "TAG IM", "App Minimized (Running as Client)", QtWidgets.QSystemTrayIcon.Information, 1000) def shutdownapp(self): if self.service == "server": self.service == "" self.broadcast("Host has shutdown") self.server.close() app.quit() elif self.service == "client": self.service == "" message = "Left the chat" self.client.send(message.encode()) self.client.close() print("Client closed manually") app.quit() elif self.service == "": app.quit() def onTrayIconActivated(self, reason): if reason == QtWidgets.QSystemTrayIcon.Trigger: self.show() self.focusWidget() def setupUI(self): mainlayout = QtWidgets.QVBoxLayout() displaybox = QtWidgets.QHBoxLayout() userlist = QtWidgets.QVBoxLayout() userlist.addWidget(QtWidgets.QLabel("Users Connected:")) userlist.addWidget(self.userwindow) displaybox.addWidget(self.chatwindow, 3) displaybox.addLayout(userlist, 1) inputbox = QtWidgets.QHBoxLayout() inputbox.addWidget(self.typingfield) inputbox.addWidget(self.sendbutton) mainlayout.addLayout(displaybox) mainlayout.addLayout(inputbox) self.setLayout(mainlayout) self.chatwindow.addItem("/host to setup server on local host (Port 7000)") self.chatwindow.addItem("/[email protected] to connect to server on local host (Port 7000)") self.chatwindow.scrollToBottom() self.typingfield.setFocus() self.setWindowTitle("TAG CHAT") def sendpressed(self): typedtext = self.typingfield.text() if typedtext: if typedtext[0] == "/": self.metaprocessor(typedtext) else: if self.service: if self.service == "server": self.broadcast(typedtext) elif self.service == "client": self.client.send(typedtext.encode()) else: self.chatwindow.addItem("Not connected to any group.") self.chatwindow.scrollToBottom() self.typingfield.clear() self.typingfield.setFocus() def metaprocessor(self, typedtext): if typedtext == "/host": serverstart = threading.Thread(target=self.makeserver, args=()) serverstart.daemon = True serverstart.start() elif typedtext[0:9] == "/connect@" and len(typedtext) > 9: userip = typedtext[9:] try: ipaddress.ip_address(userip) clientstart = threading.Thread(target=self.startclient, args=(userip, 7000)) clientstart.daemon = True clientstart.start() except ValueError: self.chatwindow.addItem("Invalid IP address provided '" + userip + "'") self.chatwindow.scrollToBottom() elif typedtext == "/quit": self.shutdownapp() else: self.chatwindow.addItem("Invalid syntax") self.chatwindow.scrollToBottom() def startclient(self, serverip, port): self.client.connect((str(serverip), port)) self.service = "client" while True: try: message = self.client.recv(4096) if message[0:10] == "~connected".encode(): connectedusers = pickle.loads(message[10:]) self.updateclientlistclient(connectedusers) else: self.unreadnotification() self.chatwindow.addItem(message.decode()) self.chatwindow.scrollToBottom() except: self.chatwindow.addItem("Host has closed the connection".decode()) self.chatwindow.scrollToBottom() self.userwindow.clear() self.service = "" break def makeserver(self): self.chatwindow.addItem("Creating server @ " + self.machineIP + ":7000") self.server.bind((self.machineIP, 7000)) self.chatwindow.addItem("Server started successfully...\nListening to all connections") self.chatwindow.scrollToBottom() self.service = "server" self.server.listen(100) while True: conn, addr = self.server.accept() message = "Connected to " + self.machineIP + ":7000" conn.send(message.encode()) self.connectedusers.append((conn, addr)) self.updateclientlistserver(self.connectedusers) newconnection = threading.Thread(target=self.startconnection, args=(conn, addr)) newconnection.daemon = True newconnection.start() def startconnection(self, conn, addr): self.chatwindow.addItem("User " + str(addr) + " has joined the group.") self.chatwindow.scrollToBottom() while True: try: data = conn.recv(4096) self.unreadnotification() self.broadcast(data.decode()) except: print("Client closing caught by server") conn.close() self.connectedusers.remove((conn, addr)) self.updateclientlistserver(self.connectedusers) break def updateclientlistserver(self, connectedusers): self.userwindow.clear() for each in connectedusers: self.userwindow.addItem(each[1][0]) def updateclientlistclient(self, connectedusers): self.userwindow.clear() for each in connectedusers: self.userwindow.addItem(each) def broadcast(self, typedtext): servermessage = self.machineIP + " : " + str(typedtext) self.chatwindow.addItem(servermessage) self.chatwindow.scrollToBottom() for each in self.connectedusers: message = each[1][0] + " : " + str(typedtext) each[0].send(message.encode()) iplist = [] for ips in self.connectedusers: iplist.append(ips[1][0]) data = pickle.dumps(iplist) each[0].send("~connected".encode() + data) def unreadnotification(self): if not self.isVisible(): self.unreadcount += 1 if time.time() - self.oldtime > 60: self.oldtime = time.time() self.tray_icon.showMessage( "TAG IM", str(self.unreadcount) + " messages unread", QtWidgets.QSystemTrayIcon.Information, 1000) else: self.unreadcount = 0 if __name__ == "__main__": # Back up the reference to the exceptionhook sys._excepthook = sys.excepthook def my_exception_hook(exctype, value, traceback): # Print the error and traceback print(exctype, value, traceback) # Call the normal Exception hook after sys._excepthook(exctype, value, traceback) sys.exit(1) # Set the exception hook to our wrapping function sys.excepthook = my_exception_hook app = QtWidgets.QApplication(sys.argv) mainApplication = MainWindow() try: sys.exit(app.exec_()) except: print("Exiting") |