Created
February 13, 2020 13:50
-
-
Save ceffiong/88899833e44797b5b91d6cd289df93b8 to your computer and use it in GitHub Desktop.
Multi-user Group Chat Server Logic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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