python - Python-Tkinter和socket.recv()循环

标签 python sockets user-interface tkinter

我正在尝试将数据发送到客户端,这是Python中聊天服务器开发过程的一部分。当前,客户端具有GUI,但是服务器是从命令行运行的。我将完整的代码包含在下面的代码中。

客户

from tkinter import *
import socket

host = socket.gethostname()
port = 8000

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

class Application(Frame):
    def __init__(self, master=None):
        #Create master frame
        Frame.__init__(self,master)
        self.grid()
        self.master.title("Test 1")
        self.conn=False #State of connection to server


        #Configure main frame
        for r in range (4):
            self.master.rowconfigure(r, weight=1)
        for c in range (2):
            self.master.columnconfigure(c)

        #Create sub frames
        TopFrame=Frame(master, bg="red")
        TopFrame.grid(row=0, column=0, rowspan=3)
        BottomFrame=Frame(master, bg="blue")
        BottomFrame.grid(row=4, column=0)
        SideFrame=Frame(master, bg="green")
        SideFrame.grid(column=1, row=0, rowspan=4)

        #Create Chat log
        self.chatlog=Text(TopFrame)
        self.chatlog.pack(padx=5, pady=5)


    #Create entry field
        self.e1=StringVar()
        self.e1=Entry(BottomFrame)
        self.e1.pack(pady=5, padx=5)

        #Create buttons
        b1=Button(SideFrame, text="Connect", command=self.connect)
        b1.grid(row=0, column=0, padx=5, pady=5)
        b2=Button(SideFrame, text="Disconnect", command=self.disconnect)
        b2.grid(row=1, column=0, padx=5, pady=5)
        b3=Button(SideFrame, text="Send", command=self.sendmessage)
        b3.grid(row=2, column=0, padx=5, pady=5)

    def connect(self): #Connect to server
        self.chatlog['state'] = NORMAL
        self.chatlog.insert(END, ("===ATTEMPTING TO CONNECT TO SERVER\n"))
        self.chatlog['state'] = DISABLED
        self.chatlog.yview(END)
        try:
            s.connect((host,port))
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===CONNECTED TO SERVER\n"))

            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)
            self.conn=True
            print("Connected") #Connection successful

            #Receive messages
            self.receive_msg()

        except ConnectionRefusedError: #Can't find server
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===SERVER COULD NOT BE FOUND\n" + "===PLEASE MAKE SURE THE SERVER IS ON, AND YOU'RE CONNECTED TO THE NETWORK\n"))
            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)
        except: #Other errors
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===THERE'S AN ERROR WITH THE PROGRAM\n" + "===PLEASE TURN IT OFF AND ON AGAIN\n"))
            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)

        # When attempting to connect a second time, produces OS error: an operation was attempted on something that is not a socket

    def disconnect(self):
        if self.conn: #Tests to see if client is connected
            s.close()
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===DISCONNECTED FROM SERVER.\n"))
            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)
            self.conn=False
        else: #Prevents attempting to disconnect when already disconnected
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===YOU AREN'T CURRENTLY CONNECTED.\n"))
            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)


    def sendmessage(self):
        if self.conn: #Prevents sending if not connected
            self.msg=self.e1.get()
            if self.msg == "": #Empty message catcher
                self.chatlog['state'] = NORMAL
                self.chatlog.insert(END, ("===YOU CANNOT SEND AN EMPTY MESSAGE.\n" ))
                self.chatlog['state'] = DISABLED
                self.chatlog.yview(END)
            else:
                self.chatlog['state'] = NORMAL
                self.chatlog.insert(END, ('You: ' + self.msg + '\n'))
                self.chatlog['state'] = DISABLED
                self.chatlog.yview(END)
                self.send_data(self.msg) #Sends message
        else:
                self.chatlog['state'] = NORMAL
                self.chatlog.insert(END, ("===YOU ARE NOT CONNECTED TO A SERVER. YOU CANNOT SEND A MESSAGE.\n" ))
                self.chatlog['state'] = DISABLED
                self.chatlog.yview(END)

    def receive_msg(self):
        #Prepared to receive message
        print("Preparing to receive")
        while 1:
            data=s.recv(1024)
            decoded_data=data.decode('UTF-8')
            print(decoded_data) #Only printing to cmd line for now, to resolve errors
            #self.mainloop() ##Only fix I've found. This loop seems to crash the mainloop used to update GUI

    def send_data(self, message):
        try:
            s.send(message.encode('UTF-8'))
        except:
                self.chatlog['state'] = NORMAL
                self.chatlog.insert(END, ("===THE PREVIOUS MESSAGE DIDN'T SEND. THIS IS POSSIBLY DUE TO A SERVER ERROR.\n"))
                self.chatlog['state'] = DISABLED
                self.chatlog.yview(END)


root = Tk()
app = Application(root)
app.mainloop()

服务器
import socket

host=socket.gethostname()
port=(8000)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

def connect():
    s.bind((host,port))
    s.listen(2)
    print("Server listening")
    conn,addr=s.accept()
    print("Connected")
    send(conn)

# def receive(conn):
#   while 1:
#       try:
#       data=conn.recv(1024)
#       decoded_data=data.decode('UTF-8')
#       if not decoded_data:
#           print("No data")
#       else:
#           print("New data")
#           print(decoded_data)

def send(conn):
    while 1:
        data=input("Input data to send: ")
        encoded_data=data.encode('UTF-8')
        conn.send(encoded_data)

我遇到的问题是,总是准备接收新消息的receive_msg()循环会停止主循环,从而使GUI保持更新。我已经评论了关于调用app.mainloop()的那行,但是这意味着我只在mainloop无限接收到receive_msg循环之前收到一条消息。谁能帮我解决问题?

最佳答案

您可以使用multiprocessing.connection Listener and Client.

像这样。

服务器

from multiprocessing.connection import Listener


listener = Listener(("", 25000), authkey=b"selam")
client = listener.accept()
while 1:
    try:
        print(client.recv_bytes())
    except EOFError:
        print("Connection closed")
        break

客户
 from multiprocessing.connection import Client

 remote = Client(("", 25000), authkey=b"selam")
 ...
 ...
 class Application(Frame):
 ...
 ...

     def sendmessage(self):
         remote.send_bytes(self.e1.get().encode('ascii'))
....

关于python - Python-Tkinter和socket.recv()循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21894705/

相关文章:

python - 在字典中添加相同键的值

java - 我在尝试使用 JSch 或 Socket 连接到 channel 时感到困惑和卡住了?

java - 如何用图形相关指令装饰TableCellRenderer?

sockets - 创建 TCP 连接的一般开销

java - 为什么即使套接字已关闭,socket.isOutputShutdown() 也会返回 false?

java - 关于可扩展前端设计方法(Spring 框架)的任何建议

javascript - 如何像轮播一样将选项卡滑入和滑出

python - scipy.optimize.leastsq : not a proper array of floats

python - 在 python 2.7 中调用超子类

python - 选择用\n 分隔的 <p> 标记