I am trying to make a simple chat application using Python 3. I have seen this work in the past, where my client is able to connect to my server, and messages can be sent successfully. I want to move the app from a script working in the python idle shell to a GUI built with TKinter. Using entry and button widgets, a client can connect to the server for a fraction of a second, then is immediately disconnected. This only seems to happen because I am trying to use tkinter.
Error message is:
%$%$ has connected.
Exception in thread Thread-33:
Traceback (most recent call last):
File "C:\Users\lmaor\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 917, in _bootstrap_inner
self.run()
File "C:\Users\lmaor\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\lmaor\Desktop\Server 2.py", line 32, in handle_client
name = client.recv(BUFSIZ).decode("utf8")
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
The client-side code is:
#Importing packages
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
import tkinter
from tkinter import *
from tkinter import messagebox
global client_socket
global HOST
global PORT
#These are here to stop the program breaking later on
HOST = 1
PORT = 1
BUFSIZ = 1024
client_socket = socket(AF_INET, SOCK_STREAM)
#This unsuccessfully connects to the server
def connect():
HOST = etyHost.get()
PORT = etyPort.get()
if not PORT:
PORT = 33000 # Default value.
else:
PORT = int(PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
#Creates a function to receive messages at any time
def receive():
while True:
try:
global client_socket
msg = client_socket.recv(BUFSIZ).decode("utf8")
msgChatlog.insert(END, msg)
except OSError:
break
#Creates a function to send messages
def send(event=None): #Event is passed by binders
msg = varMessage.get()
varMessage.set("") #Clears input field
client_socket.send(bytes(msg, "utf8"))
if msg == "{quit}":
client_socket.close()
top.quit()
#When closing window
def on_closing(event=None):
varMessage.set("{quit}")
send()
#Create tkinter window
jahchat = Tk()
jahchat.geometry("500x500")
jahchat.configure(background = "black")
jahchat.resizable(False, False)
jahchat.title("JahChat")
#
#Frame contains everything. useless
frmMessage = Frame()
#Var message is what goes into the chat
varMessage = StringVar() # For the messages to be sent.
varMessage.set("Type your messages here.")
#Scrollbar for the chatlog
srlChatlog = Scrollbar(frmMessage) # To navigate through past messages.
#
msgChatlog = Listbox(frmMessage, height=15, width=100, yscrollcommand=srlChatlog.set)
srlChatlog.pack(side=RIGHT, fill=Y)
msgChatlog.pack(side=LEFT, fill=BOTH)
msgChatlog.pack()
frmMessage.pack()
#
etyMessage= Entry(textvariable=varMessage)
etyMessage.bind("<Return>", send)
etyMessage.pack()
btnMessage = Button(text="Send", command=send)
btnMessage.pack()
#jahchat.protocol("WM_DELETE_WINDOW", on_closing)
#Entry box
etyHost = Entry(jahchat)
etyHost.pack()
etyHost.place(x = 0, y = 250)
#Entry box
etyPort = Entry(jahchat)
etyPort.pack()
etyPort.place(x = 0, y = 275)
#Button
btnConnect = Button(jahchat, text = "Connect", command = connect)
btnConnect.config(width = 20)
btnConnect.place(x = 0, y = 320)
#========================================================
#This is the code that sucessfully connects to the server
#HOST = input("host")
#PORT = input("port")
#if not PORT:
# PORT = 33000 # Default value.
#else:
# PORT = int(PORT)
#client_socket = socket(AF_INET, SOCK_STREAM)
#BUFSIZ = 1024
#ADDR = (HOST, PORT)
#print (ADDR)
#print (type(ADDR))
#client_socket.connect(ADDR)
#receive_thread = Thread(target=receive)
#receive_thread.start()
#===========================================================
jahchat.mainloop() # Starts GUI execution.
The server code is:
#Importing packages
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
#Sets up constant variables for later use
clients = {}
addresses = {}
HOST = '' #Client has to set this as their host to connect
PORT = 33000 #Client has to set this as their port to connect
BUFSIZ = 1024
ADDR = (HOST, PORT)
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)
#Creates a function that handles clients into the server
def accept_incoming_connections():
while True:
client, client_address = SERVER.accept()
print ("%$%$ has connected." .format(client_address))
client.send(bytes("Greetings from the cave!" + "Now type your name and press enter!", "utf8"))
addresses[client] = client_address
Thread(target=handle_client, args=(client,)).start()
#Takes client socket as argument.
def handle_client(client):
name = client.recv(BUFSIZ).decode("utf8")
welcome = 'Welcome %s! If you ever want to quit, type {quit} to exit.' % name
client.send(bytes(welcome, "utf8"))
msg = "%s has joined the chat!" % name
broadcast(bytes(msg, "utf8"))
clients[client] = name
while True:
msg = client.recv(BUFSIZ)
if msg != bytes("{quit}", "utf8"):
broadcast(msg, name+": ")
else:
client.send(bytes("{quit}", "utf8"))
client.close()
del clients[client]
broadcast(bytes("%s has left the chat." % name, "utf8"))
break
#Broadcasts message to whole server
def broadcast(msg, prefix=""): #Prefix is for name identification.
for sock in clients:
sock.send(bytes(prefix, "utf8")+msg)
def checkIP():
print (HOST, PORT, ADDR)
if __name__ == "__main__":
SERVER.listen(5) # Listens for 5 connections at max.
print("Waiting for connection...")
ACCEPT_THREAD = Thread(target=accept_incoming_connections)
ACCEPT_THREAD.start() #Starts the infinite loop.
ACCEPT_THREAD.join()
SERVER.close()
All answers appreciated.