recv
是网络编程中用于从套接字接收数据的核心函数,常见于 TCP/UDP 通信。以下是其概念、用法和案例详解:
概念
- 作用:从已连接(TCP)或已绑定(UDP)的套接字接收数据。
- 参数:
- bufsize: 指定接收缓冲区的大小(一次最多接收的字节数)。
- flags(可选): 控制接收行为(如
MSG_PEEK
仅查看数据不移除)。
- 返回值:
- 成功时返回接收到的字节数据(类型为
bytes
)。 - 返回空字节(如
b''
)表示连接已关闭(TCP)。 - 错误时抛出异常(如超时、连接重置)。
- 成功时返回接收到的字节数据(类型为
使用场景
- TCP 通信:需先建立连接(
connect()
/accept()
),数据可靠但需处理粘包。 - UDP 通信:无连接,需用
recvfrom
获取发送方地址,数据可能丢失或乱序。
使用案例(Python)
案例 1:TCP 客户端接收数据
import socket# 创建 TCP 客户端
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 8080))# 发送请求
client.send(b"Hello Server!")# 接收响应(最多 1024 字节)
data = client.recv(1024)
print(f"Received: {data.decode()}")client.close()
案例 2:TCP 服务器循环接收数据
import socketserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("0.0.0.0", 8080))
server.listen(1)while True:client, addr = server.accept()print(f"Connected by {addr}")while True:data = client.recv(1024) # 阻塞等待数据if not data:break # 连接关闭print(f"Received: {data.decode()}")client.send(b"ACK") # 回复确认client.close()
案例 3:UDP 接收数据(recvfrom
)
import socketudp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(("0.0.0.0", 8080))while True:data, addr = udp_socket.recvfrom(1024) # 同时获取数据和地址print(f"Received from {addr}: {data.decode()}")udp_socket.sendto(b"Reply", addr) # 向原地址回复
关键注意事项
-
阻塞与非阻塞模式:
- 默认阻塞:
recv
会一直等待数据,直到有数据或连接关闭。 - 非阻塞模式:设置
socket.setblocking(False)
,无数据时立即抛出BlockingIOError
。
- 默认阻塞:
-
处理数据不完整:
- 需循环接收,直到满足业务逻辑(如接收固定长度或特定结束符):
buffer = bytearray() while len(buffer) < expected_size:data = sock.recv(1024)if not data:breakbuffer.extend(data)
- 需循环接收,直到满足业务逻辑(如接收固定长度或特定结束符):
-
超时设置:
sock.settimeout(5.0) # 5 秒后超时,抛出 socket.timeout try:data = sock.recv(1024) except socket.timeout:print("Timeout!")
-
判断连接关闭(TCP):
recv
返回空数据(b''
)时,表示对方已关闭连接。
常见问题
- 粘包问题:TCP 是流式协议,多次
send
可能被合并接收,需自定义协议(如添加长度头)。 - 资源释放:
recv
失败后需关闭套接字,避免资源泄漏。 - 编码处理:接收的
bytes
需解码(如decode('utf-8')
),注意处理异常(如非法字符)。
掌握 recv
的细节能显著提升网络应用的健壮性和性能!