def broadcast(message, connection, list_of_clients): for clients in list_of_clients: if clients != connection: # Make sure it's not sending to itself try: chatlib.write_msg(clients, message, MAXBUFFERSIZE) except: # Can't send? clients.close() # If the link is broken, we remove the client remove(clients, list_of_clients)
def clientthread(conn, addr, clientNicknames, list_of_clients, end_event, threadStream): # Nickname collection while end_event.is_set(): dateTime = datetime.now() uniqueName = True nickname = "" message = chatlib.read_msg(conn, MAXBUFFERSIZE) nickname = message.rstrip() # Get rid of the newline if nickname == "BYE": # In case the client disconnects before making a nickname threadStream[0] = str(dateTime) + ", " + str( addr) + " Left before creating a nickname\n" remove(conn, list_of_clients) return if re.match( "^[a-zA-Z0-9]{2,30}$", nickname ): # Ensure the nickname is alphanumeric, no spaces allowed for name in clientNicknames: # Ensure the nickname is unique if name == nickname: uniqueName = False if uniqueName: chatlib.write_msg(conn, "READY", MAXBUFFERSIZE) clientNicknames.append(nickname) threadStream[0] = str(dateTime) + ", " + str( addr) + ", " + nickname + " connected.\n" message_to_send = "<" + nickname + ">" " joined the chatroom.\n" broadcast(message_to_send, conn, list_of_clients) break else: chatlib.write_msg(conn, "RETRY", MAXBUFFERSIZE) else: chatlib.write_msg(conn, "INVALID", MAXBUFFERSIZE) # Start waiting for regular messages while end_event.is_set(): try: message = chatlib.read_msg(conn, MAXBUFFERSIZE) message = message.rstrip() # Strip newlines if message == "BYE": # If client disconnects message_to_send = "<" + nickname + ">" " left the chatroom.\n" threadStream[0] = str(dateTime) + ", " + str( addr) + ", " + nickname + " disconnected.\n" broadcast(message_to_send, conn, list_of_clients) # Let everyone know clientNicknames.remove( nickname) # Remove from list of nicknames remove(conn, list_of_clients) # Remove the connection break elif message: threadStream[0] = nickname + ": " + message + "\n" # Calls broadcast function to send message to all message_to_send = "<" + nickname + "> " + message broadcast(message_to_send, conn, list_of_clients) else: # If the message is empty or broken remove the connection remove(conn, list_of_clients) except: continue return
def main(): # Creates a TCP socket server = chatlib.socket_create() try: server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.setblocking(0) except socket.error as err: print("Socket error: %s" % err) exit() # Create an event to signal subthreads to end end_event = threading.Event() end_event.set() # Checks whether sufficient arguments have been provided if (len(sys.argv) != 2) and (len(sys.argv) != 3): print "Correct usage: script, IP address, (optional) port number" exit() IP_address = str(sys.argv[1]) # Takes second argument from command prompt as port number if len(sys.argv) == 3: Port = int(sys.argv[2]) else: # Default port Port = 8888 # Binds the server to an entered IP address and at the # Specified port number. try: server.bind((IP_address, Port)) server.listen(100) except socket.error as err: print("Socket error: %s" % err) exit() list_of_clients = [] clientNicknames = [] threads = [] print("Server started successfully...") threadStream = [" "] while True: if threadStream[0] != " ": log(threadStream[0]) threadStream[0] = " " try: # Get socket conn and address from client try: conn, addr = server.accept() #add conn to list of connections list_of_clients.append(conn) chatlib.write_msg(conn, "HELLO", MAXBUFFERSIZE) try: t = threading.Thread(target=clientthread, args=(conn, addr, clientNicknames, list_of_clients, end_event, threadStream)) threads.append(t) t.start() except Exception as e: print("Error starting thread: ", e) except socket.error as err: # Catches errno11 because accept is no longer a blocking call if err.errno == 11: pass else: print("Socket error: %s" % err) except KeyboardInterrupt: # Close server message = "SERVER CLOSING IN 5 SECONDS" print("\n" + message) broadcast(message, server, list_of_clients) time.sleep( 5) # Give time for clients to see server closing warning message = "SERVER CLOSED" broadcast(message, server, list_of_clients) end_event.clear( ) # Trigger the event so that the subthreads end their while loops for t in threads: t.join() for conns in list_of_clients: conns.close() server.close() return
def setNickname(): nickname = sys.stdin.readline() chatlib.write_msg(server, nickname, MAXBUFFERSIZE) sys.stdout.flush()
print ("You may now talk in the chatroom. You may exit at anytime by using Ctrl + c.") nickSet = True elif message == "RETRY": print("That nickname is already in use. Try again.") nickSet = "RETRY" elif message == "INVALID": print("Nickname must be alphanumberic and 2-30 Characters. Try again.") nickSet = "INVALID" else: print message # Sends a nick name to the server elif nickSet == "INIT" or nickSet == "RETRY" or nickSet == "INVALID" : setNickname() nickSet = "" # If the client has a nickname then they can send messages elif nickSet == True: message = sys.stdin.readline() chatlib.write_msg(server, message, MAXBUFFERSIZE) sys.stdout.write("<You> ") sys.stdout.write(message) sys.stdout.flush() except KeyboardInterrupt: # Tells the server that the client is disconnecting chatlib.write_msg(server, "BYE", MAXBUFFERSIZE) break sys.stdout.flush() server.close() exit()