Asynchronous network framework pyuv (used to implement tcp and udp services) commonly used in python

Asynchronous network framework pyuv of common python library

what is pyuv

Official documentation: https://pyuv.readthedocs.io/en/v1.x/
Official git: https://github.com/saghul/pyuv

pyuv is a libuv-based Python asynchronous network framework that can be used to build high-performance event-driven applications. It provides functions such as event loop, asynchronous IO, timer, etc., so that developers can easily write efficient network applications.

pyuv supports TCP, UDP, IPC and other network protocols, and can easily handle a large number of concurrent connections. By using a callback-based programming model, developers can write non-blocking code to make full use of system resources and improve application performance.

In addition to network programming, pyuv also supports functions such as file system operations, process management, and signal processing. It also provides some advanced features, such as asynchronous DNS resolution, streaming operations, etc., enabling developers to handle complex network scenarios more conveniently.

Use of pyuv

pyuv is Python's uvloop event loop library, which provides a Python binding for libuv, which can achieve high-performance asynchronous IO.

The pyuv library can easily implement UDP communication

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()

We create a UDP object udp and bind it to port 12345 of the local address 127.0.0.1. We then tell the UDP object to process the data by calling the on_read() function when it is received by calling the udp.start_recv() method. In the on_read() function we simply print out the received message and close the UDP object.

Next, we send a message to our own address and port using the udp.sendto() method. Call the on_send() function after sending to check for sending errors.

pyuv listens to ipv4 and ipv6 at the same time

, if there are no differentiated requirements for IPv4 and IPv6, it is usually more convenient for a socket to listen to both IPv4 and IPv6 at the same time. pyuv itself does support listening to IPv4 and IPv6 at the same time, but you need to use the pyuv.UV_TCP_REUSEADDR flag.

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()

Main points to note:

  1. Create a TCP server and bind to ::, which means listening to all addresses, including IPv4 and IPv6
  2. Pass in the pyuv.UV_TCP_REUSEADDR flag to specify to listen to two protocols at the same time
  3. In the on_connection callback function, the client address can be obtained through the requested socket object to determine whether it is IPv4 or IPv6
  4. Running the server, you can receive IPv4 and IPv6 requests without distinction
  5. When closing the server, you need to close the socket and loop
    . If you need to distinguish the version, you can judge the socket.ip address type in the callback function, and do different processing according to IPv4 or IPv6.

Summary: Explain that using this scheme, it is also possible to distinguish between ipv4 and ipv6.

Under what circumstances do you need to bind IPv4 and IPv6 sockets separately?

Usually it is more convenient for a socket to listen to both IPv4 and IPv6 at the same time. However, in some special scenarios, it is still necessary to create IPv4 and IPv6 sockets separately:

  1. The backlog size of each socket needs to be set independently
  2. Want to limit the speed or flow control of IPv4 and IPv6 connections respectively
  3. Different performance optimizations and parameter adjustments are required for IPv4 and IPv6. For example, IPv6 may require a larger backlog size.
  4. Connection-level access control needs to be implemented based on address. Separate sockets can independently control IPv4 and IPv6 connections.
  5. There are servers with lots of IPv6 connections, but few IPv4 connections. In this scenario, sharing a socket will cause IPv4 connections to be affected by IPv6.
  6. Traffic allocation needs to be done for IP version. Separate sockets can be placed in different threads/processes to share traffic.
  7. In some systems, the implementation quality of the network stack is not high, and sharing a socket will indeed cause compatibility problems.
  8. The connection status and traffic statistics of each IP version need to be obtained independently.
  9. To disable IPv4 or IPv6 completely (reserving the possibility to disable IPv4 or IPv6 independently), the respective socket can be done with the DISABLE option.

Summary: Considering factors such as scalability, monitoring, and isolation, we choose server sockets that are bound to IPv4 and IPv6 respectively.
We can flexibly choose the best solution according to the needs of the application scenario.

Guess you like

Origin blog.csdn.net/inthat/article/details/131866502