python socket编程之---UDP通信
相比于 TCP 的面向连接、可靠传输,UDP 协议是一种无连接、不保证数据可靠性和顺序的传输方式。它更适用于对实时性要求高,但对丢包不敏感的场景,比如视频直播、在线游戏和语音通信等。Python 中的 socket 模块同样封装了 UDP 协议,为程序员提供了简便的接口来实现 UDP 通信。本文将分别介绍 UDP 通信中的客户端与服务端实现方法,并给出相应的代码示例。
客户端(Client)
UDP 客户端无需建立连接,而是直接将数据报发送到指定的服务器地址和端口。下面的示例展示了如何使用 Python 的 socket 模块实现一个简单的 UDP 客户端:
1 | import socket |
说明:
- UDP 是无连接的,因此无需调用
connect
方法,而是直接使用sendto
将数据报发送给目标地址。 - 使用
recvfrom
接收数据时,同时会返回发送方的地址信息。recvfrom
函数返回的是数据和地址的元组(tuple)
recv与recvfrom
读者可能会发现,在TCP编程中我们使用了socket.recv()
方法,但是在UDP中我们使用的是socket.recvfrom()
方法。二者有什么区别呢?
recv
方法返回data,也就是只返回数据,recvfrom
方法返回(data, addr),也就是返回数据和发送者的地址两个信息。- UDP
recv
和recvfrom
方法都可以使用。但是一般来说,需要发送者地址才能够进行回复,所以常用recvfrom
- TCP只能使用
recv
方法。由于其本身就是建立在连接上的通信,所以本身就知道双方地址。
服务端(Server)
UDP 服务端的编程也十分简单,只需要绑定端口后不断调用 recvfrom
方法即可接收来自各个客户端的数据报。下面是一个基本的 UDP 服务端示例代码:
1 | import socket |
说明:
- 服务端使用
bind
绑定到指定的 IP 地址和端口,其中"0.0.0.0"
表示监听所有网络接口。如果使用"127.0.0.1"
则仅能接收本机发送的数据报。 - 因为 UDP 是无连接协议,所以服务端不需要调用
listen
或accept
方法。 - 每个收到的数据报都包含了发送者的地址信息,可以利用该信息直接回复客户端。
UDP 通信的特点与注意事项
无连接性
UDP 不需要建立连接,每个数据报都是独立发送和接收的。这样既降低了通信延迟,又节省了连接资源。不保证可靠性
UDP 不保证数据包一定能到达,也不保证数据包的顺序。如果应用场景要求数据完整可靠,需要在应用层自行实现相应的机制。适用于实时性要求高的场景
由于传输过程中开销较小,UDP 更适用于视频会议、实时语音、在线游戏等对延迟要求较高的场景。数据报大小限制
由于 UDP 数据报需要在 IP 层进行分片与组装,因此数据包一般不宜过大,否则可能引起丢包或传输失败。通常建议数据包大小不超过 1500 字节(考虑到 MTU)。
更优雅的服务端写法
当服务端功能较复杂,需要处理大量不同逻辑时,可以采用面向对象的方式对 UDP 服务端进行封装。下面是一个使用类和多线程的 UDP 服务端示例(注意:UDP 本身是无连接的,多线程仅用于并发处理接收到的数据报):
1 | import socket |
说明:
- 通过将服务端功能封装在一个类中,可以更方便地扩展和维护代码。
- 多线程处理可以避免在处理某个数据报时阻塞其它数据的接收,不过在高并发场景下,需要注意线程调度和资源竞争问题。