Python 31 网络编程 UDP的并发-socketserver模块

Python 31 网络编程 UDP的并发-socketserver模块

旧博客Python系列

UDP用socketserver模块实现并发

TCP实现并发以后,来看多线程的UDP并发如何实现.因为UDP其实并不需要多线程来处理,因为每个UDP消息收完以后,由于没有连接,直接就结束了.但是还是要看一看socketserver模块如何使用.
首先建立连接服务

if __name__ == '__main__':
    s = socketserver.ThreadingUDPServer(ip_port, MyServer) # 改成多线程UDP对象
    s.serve_forever()   #

然后点开看ThreadingUDPServer的类是什么.
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
可见继承了ThreadingMixIn, UDPServer,最后找到TCPServer里有init方法,然后发现UDPServer竟然也是采用TCPServer的初始化方法.
不过UDPServer的类里边socket.type设置成了DGRAM,符合要求,所以现在s.socket是一个UDP对象.
UDP对象也需要绑定,所以TCP的init后边执行的bind方法也需要,但是listen似乎就不需要了.结果发现server_acitivate方法也在UDPServer里重写了,写了一行""No need to call listen() to UDP""
可见作者用了类的继承以及部分属性和方法重写,很好的重用了TCPServer类.

现在拿到s了,s.socket是一个UDPsocket对象.
下一步是执行BaseServer类里的 serve_forever()
又到了_handle_request_noblock(self)方法,继续跟踪,又到了self.get_request()方法.
对于UDP来说没有accept,结果发现UDPServer里重写了get_request()方法,这里边是这样的:

class UDPServer(TCPServer):

    """"""UDP server class.""""""

    allow_reuse_address = False

    socket_type = socket.SOCK_DGRAM  # 自己的类属性是DGRAM,不会调用BaseServer的STREAM

    max_packet_size = 8192

    def get_request(self):  # UDP的get_request,返回和TCPServer的不一样
        data, client_addr = self.socket.recvfrom(self.max_packet_size)
        return (data, self.socket), client_addr

可以看到,返回了一个元组,包含接收的数据,UDP对象的元组,和传入端地址.
然后继续跟踪,就会知道MyServer.request其实是一个元组,第一个元素是数据,第二个元素是UDPsocket对象,再发送就可以了.
这里记住无需用while 循环,因为每次都会断开.更改后的UDPserver是:

# ThreadingUDPServer
import socketserver

buffer_size = 1024
ip_port = ('127.0.0.1', 8080,)


class MyServer(socketserver.BaseRequestHandler):
    def handle(self):  # 这是一个收发消息的通信循环,还需要一个连接循环
        print(self.request)
        print('收到的消息是:', self.request[0].decode('utf-8'))
        self.request[1].sendto(self.request[0].upper(), self.client_address)

if __name__ == '__main__':
    s = socketserver.ThreadingUDPServer(ip_port, MyServer) 
    s.serve_forever()
LICENSED UNDER CC BY-NC-SA 4.0
Comment