示例#1
0
def handle_send(input_box: tk.Text):
    """
    Executed when the user presses send. It will get and clear the
    text box then send the message. The message will be put straight
    into the list of messages on the client side. This is done so that
    the message doesn't need to be sent to the server and back again.

    If the server cannot be contacted, a message is displayed to the
    user to restart.

    Parameter:
        input_box (tk.Text): Text box containing the message
    """
    msg = input_box.get("1.0", tk.END).rstrip()
    input_box.delete("1.0", tk.END)
    try:
        mp.send_msg_protocol(s, msg, NAME)
        # Create a label with the clients message and add it to the frame
        label = tk.Label(text='You:\n' + msg,
                         master=frame,
                         justify='left',
                         wraplength=LABEL_WIDTH,
                         relief='raised')
        label.pack(anchor='w')
        if msg == DISCONNECT:
            window.destroy()
            s.close()
    except ConnectionAbortedError:
        msgRcvQueue.put('Lost connection with server, please restart')
    except OSError:
        msgRcvQueue.put('Lost connection with server, please restart')
示例#2
0
def sendRoomDetails(conn: socket):
    """
    Sends the list of clients and rooms to the given connection.

    Paramters:
        conn (socket): Connection to send list to
    """
    data = tabulate([list(e.values())[1:] for e in client_list.getList()],
                    headers=client_list.getList()[0].keys())
    mp.send_msg_protocol(conn, data, NAME)
示例#3
0
def accept_connection(sock: socket):
    """
    Accepts a connection given a socket object. If the initial connection
    times out, (None, None) is returned. If the connection to get the clients
    name times out after MAX_RETIRES, then the connection is aborted.

    Parameters:
        sock (socket): The socket to connect to

    Returns:
        (socket, tuple): A tuple containing the socket object
            and address of the connecting process. Or None, None
            if the connection times out.
    """
    try:
        conn, addr = sock.accept()
    except socket.timeout:
        return (None, None)
    retries = 0
    while True:
        try:
            client_name = mp.recv_msg_protocol(conn)
            client_list.addToList(conn, client_name, DEFAULT_ROOM)
            send_help(conn)
            return (conn, addr)
        except socket.timeout:
            if retries < MAX_RETIRES:
                retries += 1
                print('Retrying...')
            else:
                # If the user takes too long to respond with a name
                # close the connection
                print(f"[CLOSING] {addr} took too long to respond")
                conn.close()
                return (None, None)
示例#4
0
def sendMsg(conn: socket, msg: str):
    """
    Given a connection and message, this will send the message to all
    clients in the chat room (except itself).

    Parameters:
        conn (socket): The client that is sending the message
        msg (str): The message to send
    """
    current_chat_room = client_list.getConnRoom(conn)
    send_list = client_list.connectionsInRoom(current_chat_room)
    send_list.remove(conn)
    if send_list:
        for c in send_list:
            mp.send_msg_protocol(c, f'{client_list.getName(conn)}:\n {msg}',
                                 NAME)
示例#5
0
def on_close():
    """
    Funciton to handle when the user closes the window instead of typing
    the DISCONNECT message. First notifies the server that you are
    disconnecting, then closes the socket and window. If the socket was already
    closed (say by the server), then simply destroy the window.
    """
    if messagebox.askokcancel("Quit", "Do you want to quit?"):
        try:
            mp.send_msg_protocol(s, DISCONNECT, NAME)
            s.close()
        except ConnectionAbortedError:
            pass
        except OSError:
            pass
        finally:
            window.destroy()
示例#6
0
def send_help(conn: socket):
    """
    Sends the help message to the inputted connection. This message tells
    the user how to use the chat room

    Parmeters:
        conn (socket): The connection to send the message to
    """
    help_message = ('Welcome to ChatRooms. The following commands'
                    ' are currently supported:\n')
    help_message += HELP_MESSAGE + '\n'
    help_message += DISSCONNECT_MESSAGE + '\n'
    help_message += MOVE_ROOM_MESSAGE + '\n'
    help_message += LEAVE_ROOM_MESSAGE + '\n'
    help_message += ROOM_DETAILS_MESSGAE + '\n'

    mp.send_msg_protocol(conn, help_message, NAME)
示例#7
0
def main():
    connected = False
    dialog = ClientSetUp()
    window.protocol("WM_DELETE_WINDOW", dialog.on_close)
    window.mainloop()
    NAME, ip, port = (dialog.name, dialog.ip, dialog.port)
    while not connected:
        try:
            port = int(port)
            addr = (ip, port)
            s.connect(addr)
            connected = True
        except ConnectionRefusedError:
            dialog.retry(name=NAME)
            NAME, ip, port = (dialog.name, dialog.ip, dialog.port)
        except ValueError:
            dialog.retry(name=NAME, ip=ip)
            NAME, ip, port = (dialog.name, dialog.ip, dialog.port)
        except Exception:
            # Assume all other exceptions are because of failed connection
            dialog.retry(name=NAME)
            NAME, ip, port = (dialog.name, dialog.ip, dialog.port)
    dialog.destroy()

    thread_recv = threading.Thread(target=handle_recv)
    thread_recv.start()
    setUpWindow()

    if not NAME:
        # If name was not entered, create a random name
        NAME = "User" + str(random.randint(0, 1000))

    # Send the first message that initialises the connection.
    # This simply involves setting the name of this client on the server.
    try:
        mp.send_msg_protocol(s, NAME, NAME)
    except Exception:
        # If this fails, the initialisation failed so client is not
        # connected to server properly
        msgRcvQueue.put('Connection not set up properlly, restart application')

    window.mainloop()
示例#8
0
def updateRoom(conn: socket, chat_room: str):
    """
    Leaves the connections current chat romm and changes to another.
    Ensures that the chat room is valid before changing for the given
    connection.

    Parameters:
        conn (socket): The client to update
        chat_room (str): The room to join prepended with {CREATE_ROOM}
    """
    new_room = chat_room[len(MOVE_ROOM):].strip()
    if new_room == client_list.getConnRoom(conn):
        # If you're moving into the same room, do nothing
        pass
    elif not new_room == '':
        leaveRoom(conn)
        client_list.updateChatRoom(conn, new_room)
        sendMsg(conn, f'{client_list.getName(conn)} has entered the chat')
    else:
        msg = f'"{new_room}" is not a valid name.'
        mp.send_msg_protocol(conn, msg, NAME)
示例#9
0
def handle_client(conn: socket, addr: tuple):
    """
    Handles the client connection in a separate thread to the one that
    accepts the connection. This thread will be responsible for processing
    what the client sends.

    Parameter:
        conn (socket): The socket that the connection is using
        addr (tuple) : The host and port tuple

    Returns:
        None
    """
    print(f'[NEW CONNECTION] {addr} has connected')
    sendMsg(conn, f'{client_list.getName(conn)} has entered the chat')

    connected = True
    while connected:
        try:
            msg = mp.recv_msg_protocol(conn)

            # If msg is not a special message then send to all.
            # Otherwise handle request based on input
            if not msg:
                # Do nothing if header was invalid
                pass
            if msg == HELP:
                send_help(conn)
            elif msg == DISCONNECT:
                connected = False
                disconnect(conn)
            elif re.match(MOVE_ROOM + "*", msg):
                updateRoom(conn, msg)
            elif msg == LEAVE_ROOM:
                leaveRoom(conn)
            elif msg == ROOM_DETAILS:
                sendRoomDetails(conn)
            else:
                sendMsg(conn, msg)
        except socket.timeout:
            # Ignore timeouts
            pass
        except ConnectionResetError:
            # This error can be thrown when the client disconnects
            connected = False
            disconnect(conn)
        except OSError:
            # Can happen if server shutsdown connction
            connected = False
            disconnect(conn)
示例#10
0
def handle_recv():
    """
    This function runs in it's own thread. It runs a blocking call
    to recieve data from the server (messages from other users). This
    call fails when the socket is closed, which happens in the other
    thread.
    """
    while True:
        try:
            data = mp.recv_msg_protocol(s)
            # Ignore if data is empty or the header was invalid
            if data:
                msgRcvQueue.put(data)
        except ConnectionAbortedError:
            break
        except OSError:
            break