如何同时发送和接收数据Python UDP socket

How to send and receive data the same time Python UDP socket

最近才知道#python,做了一个关于rasberry pi的小项目。我想通过UDP协议在服务器是笔记本电脑,客户端是Ras之间传输和接收数据,我使用Python的套接字库。从ras传输传感器数据到laptop,从laptop传输控制命令到ras。必须始终传输来自 ras 的数据,因此我使用了带有 time.sleep 的 while true 循环。问题又出现在这个时候,笔记本电脑的控制命令不是一直发送的,只有在需要的时候才会发送,我通过recvfrom()接收Ras上的控制命令也是在while True循环中,所以当不发送控制命令的时候是 while true 循环卡在这里,所以传感器的数据不能再传输了。 m.n帮我给这篇文章提意见或者关键词。谢谢。

server.py

import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip = ""
port = 5001
server_address = (ip, port)
s.bind(server_address)
while True:
    print("####### Server is listening #######")
    data, address = s.recvfrom(4096)
    print("\n\n 2. Server received: ", data.decode('utf-8'), "\n\n")
    s.sendto(send_data.encode('utf-8'), address)
    print("\n\n 1. Server sent : ", send_data, "\n\n")
    time.sleep(1)

cilent.py

import time
import socket
import random
UDP_IP = ""
UDP_PORT = 5001
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM, 0)
while True:
    roll = random.randrange(1,100)
    a = str(roll)
    s.sendto(a.encode('utf-8'), (UDP_IP, UDP_PORT))
    print("data gui:",str(roll).encode('utf-8'))
    data, address = s.recvfrom(4096)
    print("data nhan",data)
    time.sleep(1)

如果将数据从 RasPi 发送到 PC 是一个相当独立的事情,必须始终 运行,您可以考虑为其创建一个单独的执行线程,这样您就可以 sleep()在那里,通常可以做任何你想做的事,而不会干扰接收你必须响应的偶尔命令。线程的描述很好 here 但它可能看起来像这样:

#!/usr/bin/env python3

import sys
import time
import random
import logging
import threading, queue
 
def Transmitter():
    """Transmits readings to PC at 1 second intervals on a separate thread"""
    logging.debug(f'[Transmitter] Starting')

    # Start independent loop sending values
    i = 0
    while True:
       reading = random.randint(0,100)
       logging.debug(f'[Transmitter] Iteration: {i}, reading: {reading}')
       i += 1
       time.sleep(1)

if __name__ == '__main__':

    # Set up logging - very advisable with threaded code
    logging.basicConfig(level=logging.DEBUG, format='%(levelname)s %(message)s')

    # Create independent thread to transmit readings
    thr = threading.Thread(target=Transmitter, args=())
    thr.start()

    # Main loop - waiting for commands from PC
    logging.debug('[Main] Starting main loop')
    i = 0
    while True:
       # Not what you want but just showing the other thread is unaffacted by sleeping here
       time.sleep(5)

       i += 1
       logging.debug(f'[Main] Iteration: {i}')

这是样本 运行 的输出:

DEBUG [Transmitter] Starting
DEBUG [Transmitter] Iteration: 0, reading: 82
DEBUG [Main] Starting main loop
DEBUG [Transmitter] Iteration: 1, reading: 84
DEBUG [Transmitter] Iteration: 2, reading: 45
DEBUG [Transmitter] Iteration: 3, reading: 47
DEBUG [Transmitter] Iteration: 4, reading: 97
DEBUG [Main] Iteration: 1
DEBUG [Transmitter] Iteration: 5, reading: 81
DEBUG [Transmitter] Iteration: 6, reading: 20
DEBUG [Transmitter] Iteration: 7, reading: 6
DEBUG [Transmitter] Iteration: 8, reading: 16
DEBUG [Transmitter] Iteration: 9, reading: 54
DEBUG [Main] Iteration: 2
DEBUG [Transmitter] Iteration: 10, reading: 67
DEBUG [Transmitter] Iteration: 11, reading: 91
DEBUG [Transmitter] Iteration: 12, reading: 37

同样,如果您不想 hang/block 在 RasPi 上等待来自 PC 的命令,您可以启动另一个线程,该线程处于紧密循环中, 阻止从 UDP 命令端口读取。然后它可以将命令放入 Python Queue 供主程序在需要时读取,并且它可以超时读取,这意味着主线程在没有时不会阻塞传入的命令。很好的描述 here,但代码可能如下所示:

#!/usr/bin/env python3

import sys
import time
import random
import logging
import threading, queue

def Transmitter():
    """Transmits readings to PC at 1 second intervals"""
    logging.debug(f'[Transmitter] Starting')

    # Start independent loop sending values
    i = 0
    while True:
       reading = random.randint(0,100)
       logging.debug(f'[Transmitter] Iteration: {i}, reading: {reading}')
       i += 1
       time.sleep(1)

def Receiver(Q):
    """Waits for commands and queues them to the main process"""
    logging.debug(f'[Receiver] Starting')

    # Wait for commands from PC and place into queue
    while True:
       # We will actually wait a random number of seconds and then synthesize dummy command
       time.sleep(random.randint(3,7))
       cmd = f'command_{random.randint(100,200)}'
       logging.debug(f'[Receiver] Synthesizing cmd: {cmd}')
       Q.put(cmd)

if __name__ == '__main__':

    # Set up logging - very advisable with threaded code
    logging.basicConfig(level=logging.DEBUG, format='%(levelname)s %(message)s')

    # Create independent thread to transmit readings
    tx = threading.Thread(target=Transmitter, args=())
    tx.start()

    # Create independent thread to receive commands and send to us via queue
    Q = queue.Queue()
    rx = threading.Thread(target=Receiver, args=(Q,))
    rx.start()

    # Main loop - processing commands from queue
    logging.debug('[Main] Starting main loop')
    msgNum = 0
    while True:
       # Wait for a message from queue...
       # ... you can either block like I am here
       # ... or use timeout and not block
       cmd = Q.get()
       msgNum += 1
       logging.debug(f'[Main] Received cmd: {cmd} {msgNum}')

注意:我不相信 Python 套接字是 thread-safe,因此您可能希望使用这种方法在不同的端口上发送和接收 - 但这应该不是问题,因为有 65,000 个端口。