简体   繁体   English

类python之间的双向通信(已添加编辑+代码)

[英]Two-Way communication between classes python (edited + code added)

So, I have classes that need to communicate with each other. 因此,我有一些需要彼此通信的类。 For example, I build client of chat program. 例如,我建立了聊天程序的客户端。 One class handle the sockets, and another class that handle the GUI. 一类处理套接字,另一类处理GUI。 So the GUI class has to get the received data from the sockets class, and in addition has to send the messages through the socket class. 因此,GUI类必须从套接字类获取接收到的数据,此外还必须通过套接字类发送消息。

The problem is that if you make one class contain the other you cant communicate two-way. 问题是,如果使一个类包含另一个类,则无法双向通信。 You need to pass an instance of the parent into the child But I don't think that passing the instance is the right way. 您需要将父实例传递给孩子,但我认为传递实例不是正确的方法。

Whats the best what to do that? 最好的做法是什么?

Here some code for example, hope its clear (please read the comments in the code to understand better): 这里以一些代码为例,希望它清晰(请阅读代码中的注释以更好地理解):

class MainWindow:
    def __init__(self, master, username, sock):
        # Tkinter Code Here

    def insert_msg(self, data):  # d_type 1 - msg
        self.chat_textbox.insert(END, "\n%s %s" % (datetime.now().strftime('%H:%M:%S'), data))
        self.chat_textbox.see(END)

    def send_msg(self, data, d_type=SEND_ENUM.TYPE_MSG, arg=0):
        data = str(data)
        if len(data) >= 1 and d_type == SEND_ENUM.TYPE_MSG:
            try:
                self.chat_textbox.insert(END, "\n%s [Me] %s" % (datetime.now().strftime('%H:%M:%S'), data))

                # For example, here has to use send_msg method from SockHandler class
                # self.sock_handler.send_msg(data)

            except sock_handling.ConnectionError as error:
                self.chat_textbox.insert(END, "\nError: The message was not delivered", "RED")
            else:
                pass
            finally:
                self.msg_box_entry.delete(0, 'end')
                self.chat_textbox.see(END)
        elif d_type != SEND_ENUM.TYPE_MSG:
            try:
                # also here self.sock_handler.send_msg(data, d_type)
            except sock_handling.ConnectionError as error:
                pass
        else:
            pass

class SockHandler:
    def __init__(self, client_socket):
        # nothing relevant for the Q

    def send_msg(self, data, d_type=SEND_ENUM.TYPE_MSG, arg=0):
        packed_data = self.pack_data(d_type, arg, data)

        if len(data) >= 1 and d_type == SEND_ENUM.TYPE_MSG:
            try:
                self.client_socket.send(packed_data)
            except socket.error:
                raise ConnectionError("Connection Error")

            finally:
                pass

        elif d_type != SEND_ENUM.TYPE_MSG:
            try:
                self.client_socket.send(packed_data)
            except socket.error:
                raise ConnectionError("Connection Error")

    def receive_data(self):
        try:
            while True:
                recv_data = self.client_socket.recv(self.BUFFER)
                (d_type,), data = struct.unpack("!I", recv_data[:4]), recv_data[4:]
                if d_type == RECV_ENUM.TYPE_MSG:

                    # For example, here has to use insert_msg method from MainWindow class

                elif d_type == RECV_ENUM.TYPE_USER_LIST:
                    pass
                elif d_type == RECV_ENUM.TYPE_POKE:
                    pass
        except socket.error:
            self.client_socket.close()
            raise ConnectionError("Connection Error")

Why not instantiate the SockHandler as an attribute to the MainWindow ? 为什么不将SockHandler实例SockHandler MainWindow的属性?

Like this: 像这样:

class MainWindow:
    def __init__(self, master, username, sock):
        # Tkinter Code Here
        self.socket_handler = SockHandler(sock)

Now you can send messages from MainWindow using self.socket_handler.send_msg 现在您可以使用self.socket_handler.send_msgMainWindow发送消息

For receiving, have your socket store received data where that the MainWindow can retrieve it. 为了进行接收,请让套接字存储接收到的数据,以便MainWindow可以在其中检索数据。

Like this: 像这样:

class SockHandler:
    def __init__(self, client_socket):
        # nothing relevant for the Q
        self.received_messages = Queue.Queue()

Now you need to expose a way for MainWindow to access the received messages. 现在,您需要为MainWindow提供一种访问已接收消息的方法。 If you want, you can have it directly fetch the messages by querying the queue but I would prefer something like this: 如果需要,您可以通过查询队列直接获取消息,但我希望这样:

# Within the SockHandler Class
def get_next_message():
    try:
        return self.received_messages.get(True, 5)
    except:
        return None

It doesn't matter if SockHandler or MainWindow handles the Timeout exception in this method. SockHandlerMainWindow在此方法中处理Timeout异常无关紧要。 That is up to you. 那取决于你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM