多个python UDP套接字& UI

时间:2016-08-09 19:20:25

标签: python sockets widget udp

我对python很新,还处于阅读阶段。我在这里有两个问题需要讨论。我需要使用tkinter开发一个python基本用户界面,它应该在Raspberry Pi2上运行。在后台进程中我需要创建多个UDP套接字服务器&客户端也是基于python的。

当用户按任意按钮并从组合框中选择任何值时,我需要将数据发送到c ++应用程序。同样,我需要使用从C ++应用程序收到的消息更新UI。

我在python中创建了基本的UI和UDP套接字,它按预期工作。现在我需要扩展它,以便我可以将UI数据发送到UDP Socket脚本并从那里发送到C ++应用程序。

  1. 如何实例化多个UDP套接字?是否有类似于FD_SET,python中的select()?
  2. 如何从main.py脚本启动UI和后台UDP套接字脚本?
  3. 如何指定c#区域像canvas这样的实现区域为1,组合框为区域2,按钮为区域3,标签(labelframe)为区域4,位置则为不同大小。
  4. 这是我的python代码:

    from tkinter import *
    from tkinter import ttk
    
    class MainWindow(Frame):
        def __init__(self):
            Frame.__init__(self)
            self.master.title("Test")
            self.master.minsize(330, 400)
            self.grid(sticky=E+W+N+S)
    
        modeFrame = Frame(self)
        actionFrame = Frame(self)
        msgframe = Frame(self)
        modeFrame.pack(side="top", fill="x")
        actionFrame.pack(side="top", fill="x")
        msgframe.pack(side="top", fill="x")
    
        # Mode Frame
        Label(modeFrame, text="Mode :", font="bold").pack(side="left")
    
        modeFrame.canvas1 = Canvas(modeFrame, height=25, width=25)
        modeFrame.setupled = modeFrame.canvas1.create_oval(5, 5, 20, 20, fill="green")
        modeFrame.canvas1.pack(side="left")
        Label(modeFrame, text="Setup Mode").pack(side="left")
    
        modeFrame.canvas2 = Canvas(modeFrame, height=25, width=25)
        modeFrame.setupled = modeFrame.canvas2.create_oval(5, 5, 20, 20, fill="black")
        modeFrame.canvas2.pack(side="left")
        Label(modeFrame, text="Run Mode").pack(side="left")
    
        # Action Frame
        Label(self, text="Select Coupon").pack(side="left")
        self.value_of_combo = 'X'
        self.combo("a,b,c")
        Button(self, text="Accept", command=acceptCallback).pack(side="left")
        Button(self, text="Reject", command=rejectCallback).pack(side="left")
        Button(self, text="EndSession", command=endSessionCallback).pack(fill="both", expand="yes", side="bottom")
    
        # Message Frame
        self.label0frame = LabelFrame(msgframe, text="ID")
        self.label0frame.pack(fill="both", expand="yes")
        Label(self.label0frame, text="Waiting for Client ...").pack(side="left")
    
        self.label1frame = LabelFrame(msgframe, text="Available Coupons")
        self.label1frame.pack(fill="both", expand="yes")
        Label(self.label1frame, text="Waiting for Client ...").pack(side="left")
    
        self.label2frame = LabelFrame(msgframe, text="Scanned Code")
        self.label2frame.pack(fill="both", expand="yes")
        Label(self.label2frame, text="Scanned Code ...").pack(side="left")
    
        self.label3frame = LabelFrame(msgframe, text="Status")
        self.label3frame.pack(fill="both", expand="yes")
        Label(self.label3frame, text="Status Message ...").pack(side="left")
    
    
    def newselection(self, event):
        self.value_of_combo = self.comboBox.get()
        print(self.value_of_combo)
    
    def combo(self,Values):
        self.box_value = StringVar()
        self.comboBox = ttk.Combobox(self, state="readonly", values=("a", "b", "c")) 
        self.comboBox.pack(side="left")
        self.comboBox.set("a")
        self.comboBox.bind("<<ComboboxSelected>>", self.newselection)
    
    def acceptCallback():
        print("send Accept Message to C++")
    
    def rejectCallback():
        print("send Reject Message to C++")
    
    def endSessionCallback():
        print("send EndSession Message to C++")
    
    if __name__ == "__main__":
        app = MainWindow()
        app.mainloop()
    

    UDP套接字代码:

    import time
    import struct
    import socket
    import sys
    
    MYPORT = 51506
    MYGROUP_4 = '225.0.0.1'
    
    MYTTL = 1 # Increase to reach other networks
    
    def UDPmain():
        udpApp = udpsocket()
    
    class udpsocket():
        def __init__(self):
            print('UDP Socket started')
            group = MYGROUP_4
            self.receiver('225.0.0.1')
    
    def sender(group):
        addrinfo = socket.getaddrinfo(group, None)[0]
    
        s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
    
        # Set Time-to-live (optional)
        ttl_bin = struct.pack('@i', MYTTL)
        if addrinfo[0] == socket.AF_INET: # IPv4
            s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl_bin)
        else:
            s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin)
    
        while True:
            data = repr(time.time())
            s.sendto(data + '\0', (addrinfo[4][0], MYPORT))
            time.sleep(1)
    
    
    def receiver(self,group):
        print('Receiver')
        # Look up multicast group address in name server and find out IP version
        addrinfo = socket.getaddrinfo(group, None)[0]
    
        # Create a socket
        s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
    
        # Allow multiple copies of this program on one machine
        # (not strictly needed)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
        # Bind it to the port
        s.bind(('', MYPORT))
    
        group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
        # Join group
        if addrinfo[0] == socket.AF_INET: # IPv4
            mreq = group_bin + struct.pack('=I', socket.INADDR_ANY)
            s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
        else:
            mreq = group_bin + struct.pack('@I', 0)
            s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
    
        # Loop, printing any data we receive
        while True:
            data, sender = s.recvfrom(1500)
            while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's
            print (str(sender) + '  ' + repr(data))
    

    请查看我提到的用户界面和评论

    enter image description here

    我很感激那些经历过整个问题的人。很抱歉保持很久

1 个答案:

答案 0 :(得分:1)

  1. Python也可以使用select:请参阅https://docs.python.org/3.4/library/select.html?highlight=select.select#select.select FD_SET内容为您处理;您只需提供文件描述符(或文件对象)列表。

  2. 这里有几种选择。一种是简单地将其他脚本直接合并到主代码中,并使用multiprocessing来调用它们的入口点。 https://docs.python.org/3.4/library/multiprocessing.html?highlight=multiprocess#the-process-class如果您希望单独调用它们,还有其他选项,具体取决于您的操作系统(os.spawnos.fork + os.execlsubprocess

  3. 将(3)留给知道tkinter内容的其他人。