2. UDP回显客户端最小实现

UDP回显客户端最小实现 学习卡片

UDP回显客户端最小实现

UDP客户端与TCP客户端最本质的区别在于:UDP客户端不需要调用connect()建立连接,只需在发送时指定目标地址和端口即可。下面用Python实现一个最小UDP回显客户端,向服务端发送一条文本消息并接收回显。

核心代码

import socket

# 1. 创建UDP套接字(SOCK_DGRAM表示数据报)
client_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 2. 设置接收超时,避免服务端无响应时永久阻塞
client_sock.settimeout(3.0)

# 3. 指定服务端地址(示例:本机回显服务端监听9999端口)
server_addr = ("127.0.0.1", 9999)

# 4. 发送文本消息(无需connect,直接sendto指定目标)
message = "Hello UDP Echo"
client_sock.sendto(message.encode("utf-8"), server_addr)
print(f"[发送] 目标={server_addr} 内容={message!r}")

# 5. 接收回显数据报
try:
    data, addr = client_sock.recvfrom(1024)
    print(f"[接收] 来源={addr} 内容={data.decode('utf-8')!r}")
    print(f"[校验] 回显一致: {data.decode('utf-8') == message}")
except socket.timeout:
    print("[超时] 3秒内未收到回显,请确认服务端已启动")

# 6. 关闭套接字
client_sock.close()

关键点说明

  • 无需connect:UDP客户端每次sendto都携带目标地址,套接字本身不绑定对端,因此同一个套接字可以向不同服务端发送数据。
  • sendto参数:第一个参数是字节串(需encode),第二个参数是(IP, 端口)元组。
  • recvfrom返回值:返回(data, addr),addr是发送方地址,可用于确认回显来源。
  • 超时保护:UDP不可靠,服务端未启动时不会有错误提示,必须用settimeout避免永久阻塞。
运行前请确保例1的UDP回显服务端已在127.0.0.1:9999监听。若服务端未启动,客户端将在3秒后打印超时提示,这正是UDP"无连接、无握手"特性的直接体现。
UDP 客户端 socket(AF_INET, SOCK_DGRAM) 创建套接字 settimeout(3.0) sendto(msg, addr) recvfrom(1024) close() UDP 回显服务端 bind(127.0.0.1:9999) recvfrom(1024) sendto(data, addr) 循环等待 sendto("Hello UDP Echo") 目标: 127.0.0.1:9999 recvfrom() 返回回显数据 来源: 127.0.0.1:9999 无连接:无握手 / 无状态 每次sendto独立携带目标地址 超时 → 打印提示并退出

运行与验证

先启动例1的服务端,再运行本客户端,预期输出:

[发送] 目标=('127.0.0.1', 9999) 内容='Hello UDP Echo'
[接收] 来源=('127.0.0.1', 9999) 内容='Hello UDP Echo'
[校验] 回显一致: True

若只启动客户端不启动服务端,3秒后输出[超时] 3秒内未收到回显,请确认服务端已启动。这说明UDP发送操作本身不会报错——数据报被"扔出去"后,客户端无法从sendto的返回值判断服务端是否收到,可靠性需由应用层自行保障。

与TCP客户端的对比:TCP客户端必须先connect()完成三次握手,之后用send()/recv();UDP客户端跳过connect,直接用sendto()/recvfrom(),每次调用都显式指定或获取对端地址。这就是"无连接"在代码层面的直接体现。