Skip to content

Instantly share code, notes, and snippets.

@ceffiong
Created February 13, 2020 13:50
Show Gist options
  • Save ceffiong/88899833e44797b5b91d6cd289df93b8 to your computer and use it in GitHub Desktop.
Save ceffiong/88899833e44797b5b91d6cd289df93b8 to your computer and use it in GitHub Desktop.
Multi-user Group Chat Server Logic
import tkinter as tk
import socket
import threading
window = tk.Tk()
window.title("Sever")
# Top frame consisting of two buttons widgets (i.e. btnStart, btnStop)
topFrame = tk.Frame(window)
btnStart = tk.Button(topFrame, text="Connect", command=lambda : start_server())
btnStart.pack(side=tk.LEFT)
btnStop = tk.Button(topFrame, text="Stop", command=lambda : stop_server(), state=tk.DISABLED)
btnStop.pack(side=tk.LEFT)
topFrame.pack(side=tk.TOP, pady=(5, 0))
# Middle frame consisting of two labels for displaying the host and port info
middleFrame = tk.Frame(window)
lblHost = tk.Label(middleFrame, text = "Host: X.X.X.X")
lblHost.pack(side=tk.LEFT)
lblPort = tk.Label(middleFrame, text = "Port:XXXX")
lblPort.pack(side=tk.LEFT)
middleFrame.pack(side=tk.TOP, pady=(5, 0))
# The client frame shows the client area
clientFrame = tk.Frame(window)
lblLine = tk.Label(clientFrame, text="**********Client List**********").pack()
scrollBar = tk.Scrollbar(clientFrame)
scrollBar.pack(side=tk.RIGHT, fill=tk.Y)
tkDisplay = tk.Text(clientFrame, height=15, width=30)
tkDisplay.pack(side=tk.LEFT, fill=tk.Y, padx=(5, 0))
scrollBar.config(command=tkDisplay.yview)
tkDisplay.config(yscrollcommand=scrollBar.set, background="#F4F6F7", highlightbackground="grey", state="disabled")
clientFrame.pack(side=tk.BOTTOM, pady=(5, 10))
server = None
HOST_ADDR = "0.0.0.0"
HOST_PORT = 8080
client_name = " "
clients = []
clients_names = []
# Start server function
def start_server():
global server, HOST_ADDR, HOST_PORT # code is fine without this
btnStart.config(state=tk.DISABLED)
btnStop.config(state=tk.NORMAL)
threading._start_new_thread(listen_for_client_connection, (server, HOST_ADDR, HOST_PORT))
lblHost["text"] = "Host: " + HOST_ADDR
lblPort["text"] = "Port: " + str(HOST_PORT)
# Stop server function
def stop_server():
global server
btnStart.config(state=tk.NORMAL)
btnStop.config(state=tk.DISABLED)
# MAIN SERVER LOGIC STARTS
def listen_for_client_connection(the_server, host, port):
the_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
the_server.bind((host, port))
the_server.listen(5) # server is listening for client connection
accept_clients(the_server)
# Start a new thread for accepting new client connections
def accept_clients(the_server):
while True:
client, addr = the_server.accept()
clients.append(client)
# use a thread so as not to clog the gui thread
threading._start_new_thread(send_receive_client_message, (client, addr))
# Return the index of the current client in the list of clients
def get_client_index(client_list, curr_client):
idx = 0
for conn in client_list:
if conn == curr_client:
break
idx = idx + 1
return idx
# Update client name display when a new client connects OR
# When a connected client disconnects
def update_client_names_display(name_list):
tkDisplay.config(state=tk.NORMAL)
tkDisplay.delete('1.0', tk.END)
for c in name_list:
tkDisplay.insert(tk.END, c+"\n")
tkDisplay.config(state=tk.DISABLED)
# Function to receive message from current client AND
# Send that message to other clients
def send_receive_client_message(client_connection, client_ip_addr):
global server, client_name, clients, clients_addr
client_msg = " "
# send welcome message to client
client_name = client_connection.recv(4096)
client_connection.send("Welcome " + client_name + ". Use 'exit' to quit")
clients_names.append(client_name)
update_client_names_display(clients_names) # update client names display
while True:
data = client_connection.recv(4096)
if not data: break
if data == "exit": break
client_msg = data
idx = get_client_index(clients, client_connection)
sending_client_name = clients_names[idx]
for c in clients:
if c != client_connection:
c.send(sending_client_name + "->" + client_msg)
# find the client index then remove from both lists(client name list and connection list)
idx = get_client_index(clients, client_connection)
del clients_names[idx]
del clients[idx]
client_connection.send("BYE!")
client_connection.close()
update_client_names_display(clients_names) # update client names display
window.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment