文章目录
python常用库之异步网络框架pyuv
什么是pyuv
官方文档:https://pyuv.readthedocs.io/en/v1.x/
官方git:https://github.com/saghul/pyuv
pyuv是一个基于libuv的Python异步网络框架,可以用于构建高性能的事件驱动应用程序。它提供了事件循环、异步IO、定时器等功能,使开发人员能够方便地编写高效的网络应用程序。
pyuv支持TCP、UDP、IPC等多种网络协议,并且可以轻松地处理大量的并发连接。通过使用基于回调的编程模型,开发人员可以编写非阻塞的代码,从而充分利用系统资源,提高应用程序的性能。
除了网络编程,pyuv还支持文件系统操作、进程管理和信号处理等功能。它还提供了一些高级特性,如异步DNS解析、流式操作等,使开发人员能够更方便地处理复杂的网络场景。
pyuv的使用
pyuv是Python的uvloop事件循环库,它提供了libuv的Python绑定,可以实现高性能的异步IO。
pyuv库可以很方便地实现UDP通信
import pyuv
def on_read(handle, data, addr, flags):
print("Received message:", data.decode())
handle.close()
def on_send(handle, error):
if error:
print("Send error:", pyuv.errno.strerror(error))
else:
print("Message sent")
loop = pyuv.Loop.default_loop()
udp = pyuv.UDP(loop)
udp.bind(("0.0.0.0", 12345))
udp.start_recv(on_read)
message = b"Hello, UDP!"
udp.sendto(("127.0.0.1", 12345), message, on_send)
loop.run()
我们创建了一个UDP对象udp,并将其绑定到本地地址127.0.0.1的端口12345上。然后,我们通过调用udp.start_recv()方法告诉UDP对象在接收到数据时调用on_read()函数来处理数据。在on_read()函数中,我们简单地打印出接收到的消息并关闭UDP对象。
接下来,我们使用udp.sendto()方法发送一条消息给自己的地址和端口。在发送完成后调用on_send()函数来检查是否有发送错误。
pyuv同时监听ipv4和ipv6
,如果对IPv4和IPv6完全没有差异化要求,通常一个socket同时监听IPv4和IPv6是更方便的做法。pyuv本身确实支持同时监听IPv4和IPv6,但是需要使用 pyuv.UV_TCP_REUSEADDR 标志。
import pyuv
def on_connection(server, error):
# 处理连接逻辑
pass
loop = pyuv.Loop()
server = pyuv.TCP(loop)
server.bind(("::", 8000), pyuv.UV_TCP_REUSEADDR)
server.listen(on_connection)
print("服务器启动,监听端口8000")
print("同时支持IPv4和IPv6")
try:
loop.run()
except KeyboardInterrupt:
pass
server.close()
loop.close()
主要注意点:
- 创建TCP服务器,并绑定到::,这表示监听所有地址,包括IPv4和IPv6
- 传入pyuv.UV_TCP_REUSEADDR标志,指定同时监听两种协议
- 在on_connection回调函数中,可以通过请求的socket对象获取客户端地址,以判断是IPv4还是IPv6
- 运行服务器,则可以接收IPv4和IPv6请求,无需区分对待
- 关闭服务器时需要关闭socket和loop
如果需要区分版本,可以在回调函数中判断socket.ip地址类型,根据IPv4或IPv6做不同处理。
总结:说明,使用这种方案,也可以区分是ipv4和ipv6。
什么情况需要分别绑定IPv4和IPv6 socket
通常一个socket同时监听IPv4和IPv6是更方便的做法。但是在某些特殊场景下,还是需要分别创建IPv4和IPv6的socket:
- 需要独立设置每个socket的backlog大小
- 想对IPv4和IPv6连接分别做限速或流控
- 需要对IPv4和IPv6做不同的性能优化和参数调整。比如IPv6可能需要一个更大的backlog大小。
- 需要基于地址实施连接级的访问控制。分别的socket可以单独控制IPv4和IPv6的连接。
- 有的服务器具有大量IPv6连接,但很少IPv4连接。这个场景下,共用一个socket会让IPv4连接受到IPv6的影响。
- 需要针对IP版本进行流量分配。分别的socket可以放在不同的线程/进程来分担流量。
- 有的系统网络栈实现质量不高,共用一个socket确实会有兼容性问题。
- 需要独立获取每个IP版本的连接状态和流量统计。
- 想完全禁用IPv4或IPv6( 预留独立禁用IPv4或IPv6的可能性),分别的socket可以通过DISABLE选项完成。
总结:考虑扩展性、监控、隔离等因素,才选择分别绑定IPv4和IPv6的服务器socket。
我们可以根据应用场景需要,灵活选择最佳方案。