Bottom Page

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
 Issues in Chat App for Local Network
#1
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("/connect@xxx.xxx.x.xxx 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
Quote
#2
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.
iMuny likes this post
Quote
#3
(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("/connect@xxx.xxx.x.xxx 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")
Quote

Top Page

Possibly Related Threads...
Thread Author Replies Views Last Post
  Server and Network (socket) [WinError 10053] Timxxx 1 152 Yesterday, 10:03 AM
Last Post: iMuny
  creation of an application for lora sever network moez 3 319 Apr-18-2019, 11:05 AM
Last Post: buran
  Server and Network (socket) [WinError 10053] SheeppOSU 2 592 Apr-13-2019, 09:23 PM
Last Post: SheeppOSU
  Need to build a ping test for work network austina2 2 635 Mar-11-2019, 06:58 PM
Last Post: austina2
  Assistance with Python Network script cscecela 2 865 Feb-24-2019, 01:23 AM
Last Post: searching1
  How to run local python script to remote machine without sending krishna1989 1 719 Feb-21-2019, 05:18 PM
Last Post: marienbad
  A virtual network to use with python to learn about networking with python? marienbad 0 318 Feb-11-2019, 09:20 PM
Last Post: marienbad
  Run interpreter from Network? JP_ROMANO 3 633 Nov-14-2018, 02:50 AM
Last Post: wavic
  Multiple network socket servers? MuntyScruntfundle 1 507 Nov-13-2018, 03:46 PM
Last Post: wavic
  Is it possible to trun local internet access off programmatically? Larz60+ 4 652 Sep-25-2018, 08:10 AM
Last Post: DeaD_EyE

Forum Jump:


Users browsing this thread: 1 Guest(s)