Переменная проблема передачи между чатом и интерфейсом - PullRequest
0 голосов
/ 12 мая 2019

Я написал p2p-чат, в котором вы общаетесь из окна консоли, а затем решил создать интерфейс для этого.После того, как я сделал интерфейс, я попытался отобразить сообщения на интерфейсе, а не в окне консоли, но что бы я ни пытался, я не смог добиться никакого прогресса.(И интерфейс, и чат отлично работают сами по себе)

это код для интерфейса

    from tkinter import *
    import time

    default_window_size = "400x300"
    user_name = "Default"

    class ChatInterface(Frame):

        def __init__(self, master=None):
            Frame.__init__(self, master)
            self.master = master

            # sets default bg for top level windows
            self.tl_bg = "#EEEEEE"
            self.tl_bg2 = "#EEEEEE"
            self.tl_fg = "#000000"
            self.font = "Verdana 10"

            menu = Menu(self.master)
            self.master.config(menu=menu, bd=5)
    # Menu bar


        # Options
            options = Menu(menu, tearoff=0)
            menu.add_cascade(label="Options", menu=options)
            options.add_command(label="Clear Chat", command=self.clear_chat)
            options.add_separator()
            options.add_command(label="Exit", command=self.client_exit)

        # Chat interface
            # frame containing text box with messages and scrollbar
            self.text_frame = Frame(self.master, bd=6)
            self.text_frame.pack(expand=True, fill=BOTH)

            # scrollbar for text box
            self.text_box_scrollbar = Scrollbar(self.text_frame, bd=0)
            self.text_box_scrollbar.pack(fill=Y, side=RIGHT)

            # contains messages
            self.text_box = Text(self.text_frame, yscrollcommand=self.text_box_scrollbar.set, state=DISABLED,
                                 bd=1, padx=6, pady=6, spacing3=8, wrap=WORD, bg=None, font="Verdana 10", relief=GROOVE,
                                 width=10, height=1)
            self.text_box.pack(expand=True, fill=BOTH)
            self.text_box_scrollbar.config(command=self.text_box.yview)

            # frame containing user entry field
            self.entry_frame = Frame(self.master, bd=1)
            self.entry_frame.pack(side=LEFT, fill=BOTH, expand=True)

            # entry field
            self.entry_field = Entry(self.entry_frame, bd=1, justify=LEFT)
            self.entry_field.pack(fill=X, padx=6, pady=6, ipady=3)
            # self.users_message = self.entry_field.get()

            # frame containing send button
            self.send_button_frame = Frame(self.master, bd=0)
            self.send_button_frame.pack(fill=BOTH)

            # frame containing send button
            self.send_button_frame = Frame(self.master, bd=0)
            self.send_button_frame.pack(fill=BOTH)

            # send button
            self.send_button = Button(self.send_button_frame, text="Send", width=6, relief=GROOVE, bg='white',
                                      bd=1, command=lambda: self.send_message(None), activebackground="#FFFFFF",
                                      activeforeground="#000000")
            self.send_button.pack(side=LEFT, ipady=5)
            self.master.bind("<Return>", self.send_message_event)

        def last_sent_label(self, date):

            try:
                self.sent_label.destroy()
            except AttributeError:
                pass

            self.sent_label = Label(self.entry_frame, font="Verdana 7", text=date, bg=self.tl_bg2, fg=self.tl_fg)
            self.sent_label.pack(side=LEFT, fill=X, padx=3)



    # File functions
        def client_exit(self):
            exit()

        # clears chat
        def clear_chat(self):
            self.text_box.config(state=NORMAL)
            self.last_sent_label(date="No messages sent.")
            self.text_box.delete(1.0, END)
            self.text_box.delete(1.0, END)
            self.text_box.config(state=DISABLED)

    # Send Message

        # allows "enter" key for sending msg
        def send_message_event(self, event):
            self.send_message(user_name)

        # joins username with message into publishable format
        def send_message(self, username):

            user_input = self.entry_field.get()

            global user_name
            username = user_name + ": "
            message = (username, user_input)
            readable_msg = ''.join(message)
            readable_msg.strip('{')
            readable_msg.strip('}')

            # clears entry field, passes formatted msg to send_message_insert
            if user_input != '':
                self.entry_field.delete(0, END)
                self.send_message_insert(readable_msg)

        # inserts user input into text box
        def send_message_insert(self, message):

            self.text_box.configure(state=NORMAL)
            self.text_box.insert(END, message + '\n')
            self.last_sent_label(str(time.strftime( "Last message sent: " + '%B %d, %Y' + ' at ' + '%I:%M %p')))
            self.text_box.see(END)
            self.text_box.configure(state=DISABLED)

    root = Tk()
    root.title("Chat GUI")
    root.geometry(default_window_size)
    print(default_window_size)
    root.minsize(360,200)

    a = ChatInterface(root)

    root.mainloop()

И это код для клиента

    import socket
    import threading
    import errno
    import sys



    HEADER_LENGTH = 10

    IP = "127.0.0.1"
    PORT = 5000

    current_username = input("Username: ")

    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((IP, PORT))
    client_socket.setblocking(False)

    username = current_username.encode('utf-8')
    username_header = f"{len(username):<{HEADER_LENGTH}}".encode('utf-8')
    client_socket.send(username_header + username)


    def senddata():
        while True:

            message = input(f'{current_username} > ')

            if message == "-Users":
                f = open('Connections.txt')
                print()
                for line in f:
                    print(line)
                f.close()

            elif message:

                message = message.encode('utf-8')
                message_header = f"{len(message):<{HEADER_LENGTH}}".encode('utf-8')
                client_socket.send(message_header + message)


    def receivedata():
        while True:
                try:

                    while True:

                        username_header = client_socket.recv(HEADER_LENGTH)

                        if not len(username_header):
                            print('Connection closed by the server')
                            sys.exit()

                        username_length = int(username_header.decode('utf-8').strip())
                        username = client_socket.recv(username_length).decode('utf-8')

                        message_header = client_socket.recv(HEADER_LENGTH)
                        message_length = int(message_header.decode('utf-8').strip())
                        message = client_socket.recv(message_length).decode('utf-8')

                        if message[0] == "@":
                            i = 1
                            while message[i] != " ":
                                i += 1
                            target =  message[1:i]

                            if target == current_username:
                                realmessage = message[i + 1:len(message)]
                                sys.stdout.write('\r' + f'{username} > {realmessage}' + '\n')
                        else:
                            sys.stdout.write('\r' + f'{username} > {message}' + '\n')


                except IOError as e:
                    if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
                        print('Reading error: {}'.format(str(e)))
                        sys.exit()

                    continue

                except Exception as e:
                    print('Reading error: '.format(str(e)))
                    sys.exit()

    recv_thread = threading.Thread(target=receivedata)        
    recv_thread.setDaemon(True)       
    recv_thread.start()
    senddata()

И, наконец, это серверный код

    import socket
    import select
    import datetime

    HEADER_LENGTH = 10

    IP = "127.0.0.1"
    PORT = 5000

    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    server_socket.bind((IP, PORT))

    server_socket.listen()

    # List of sockets
    sockets_list = [server_socket]

    # List of clients
    clients = {}

    f = open('Connections.txt', 'w')
    f.close()
    f = open('Messages.txt', 'w')
    f.close()

    print(f'Listening for connections on {IP}:{PORT}...')

    def receive_message(client_socket):

        try:

            message_header = client_socket.recv(HEADER_LENGTH)
            if not len(message_header):
                return False

            message_length = int(message_header.decode('utf-8').strip())
            return {'header': message_header, 'data': client_socket.recv(message_length)}

        except:
            return False

    while True:

        read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)

        for notified_socket in read_sockets:

            if notified_socket == server_socket:
                client_socket, client_address = server_socket.accept()

                user = receive_message(client_socket)

                # If Client disconnected before he sent his name
                if user is False:
                    continue

                sockets_list.append(client_socket)
                clients[client_socket] = user

                f = open('Connections.txt', 'a')
                f.write('IP: {}:{}, Username: {}'.format(*client_address, user['data'].decode('utf-8')) + '\n')
                f.close()
                print('Accepted new connection from {}:{}, username: {}'.format(*client_address,
                                                                                user['data'].decode('utf-8')))

            else:

                message = receive_message(notified_socket)

                if message is False:
                    print('Closed connection from: {}'.format(clients[notified_socket]['data'].decode('utf-8')))
                    sockets_list.remove(notified_socket)
                    del clients[notified_socket]
                    continue

                user = clients[notified_socket]

                f = open('Messages.txt', 'a')
                now = datetime.datetime.now()
                now = now.strftime("%H:%M:%S")
                f.write(user['data'].decode('utf-8') + ' (' + now + '): ' + message["data"].decode("utf-8") + '\n')
                f.close()
                print(f'Received message from {user["data"].decode("utf-8")}: {message["data"].decode("utf-8")}')

                for client_socket in clients:

                    # Don't send the message to sender
                    if client_socket != notified_socket:
                       client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])

            for notified_socket in exception_sockets:
                sockets_list.remove(notified_socket)
                del clients[notified_socket]

Мне очень жаль, что я делюсь всем кодом, но я не уверен, что мне следует поделиться в этом пункте, так как я не мог понять, что делать.

Я просто хочу выбрать имя пользователя из интерфейса и отправлять / получать сообщения из интерфейса, а не из окна консоли, вот и все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...