python实现非塞UDP通信的两种方法

当使用阻塞式UDP socket时无法执行多任务处理,也无法与用户交互,甚至不能响应ctrl+c中断。为了解决这些问题所以要用非阻塞式udp通信。
1,多线程法

import socket
import signal
import threading
import time

def handler(signal_received, frame):
    # Handle any cleanup here
    if signal_received == signal.SIGINT:
        print('SIGINT or CTRL-C detected. Exiting gracefully')
        exit(0)

def task(host, port):
    print("udp server is listen on " + str(host) + ':' + str(port))

    sock = socket.socket(socket.AF_INET, # Internet
                        socket.SOCK_DGRAM) # UDP
    sock.bind((UDP_IP, UDP_PORT))

    while True:
        data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
        print("from %s received message: %s" % (addr, data))

if __name__ == '__main__':
    signal.signal(signal.SIGINT, handler=handler) # ctlr + c

    UDP_IP = "0.0.0.0"
    UDP_PORT = 5005

    t = threading.Thread(target=task, args=(UDP_IP, UDP_PORT))
    t.daemon = True
    t.start()

    while True:
        time.sleep(100)

2, 协程法
官方文档说不要在应用中使用asyncio,而是应该在框架中用

import asyncio

class EchoServerProtocol:
    def __init__(self, message, on_con_lost):
        self.message = message
        self.on_con_lost = on_con_lost
        self.transport = None

    def connection_made(self, transport):
        self.transport = transport

    def datagram_received(self, data, addr):
        print('Received %r from %s' % (data.decode(), addr))
        self.transport.sendto(data, addr)
    def error_received(self, exc):
        print('Error received:', exc)
    def connection_lost(self, exc):
        print("Connection closed")
        self.on_con_lost.set_result(True)

async def main():
    print("Starting UDP server")

    # Get a reference to the event loop as we plan to use
    # low-level APIs.
    loop = asyncio.get_running_loop()
    on_con_lost = loop.create_future()
    message = 'Hello World!'
    # One protocol instance will be created to serve all
    # client requests.
    transport, protocol = await loop.create_datagram_endpoint(
        lambda: EchoServerProtocol(message, on_con_lost=on_con_lost),
        local_addr=('127.0.0.1', 9999),
        remote_addr=('127.0.0.1', 5005))

    try:
        while True:
            await asyncio.sleep(10)  # Serve for 1 hour.
    finally:
        transport.close()

try:
    asyncio.run(main())
except KeyboardInterrupt:
    print('Got signal: SIGINT, shutting down.')
    exit(0)

发表回复