socket.send未发送全部数据的场景及复现方法问询
如何复现socket.send()不发送全部数据的场景
要复现send()仅发送部分数据的情况,核心是让发送端的TCP发送缓冲区没有足够空间一次性容纳所有待发送数据,以下是几种可靠的实现方式:
方法1:使用非阻塞Socket发送超缓冲区数据
将Socket设置为非阻塞模式后,当待发送数据超过当前发送缓冲区剩余容量时,send()会立即返回已发送的字节数(小于总长度),不会阻塞等待。
示例代码:
import socket # 创建TCP Socket并设置为非阻塞模式 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 8080)) s.setblocking(False) # 准备远大于默认缓冲区容量的数据(1MB) large_data = b"X" * 1024 * 1024 try: sent_bytes = s.send(large_data) print(f"实际发送字节数: {sent_bytes}, 总数据长度: {len(large_data)}") if sent_bytes < len(large_data): print("成功复现部分发送场景") except BlockingIOError: print("缓冲区已满,无数据可发送")
方法2:控制接收端的TCP窗口大小
通过让接收端的接收缓冲区填满,迫使TCP接收窗口缩小,发送端的send()会因对方无法接收全部数据而返回部分发送结果。
接收端代码(故意不读取数据):
import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(("localhost", 8080)) server.listen(1) conn, addr = server.accept() # 不调用recv(),让接收缓冲区被填满 input("按任意键开始读取数据...") conn.recv(1024 * 1024)
发送端代码:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 8080)) # 发送512KB数据 large_data = b"X" * 1024 * 512 sent_bytes = s.send(large_data) print(f"实际发送字节数: {sent_bytes}, 总数据长度: {len(large_data)}")
方法3:手动缩小发送缓冲区容量
通过SO_SNDBUF选项将发送缓冲区设置为很小的值,再发送超过该容量的数据,非阻塞模式下会直接返回部分发送结果。
示例代码:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 8080)) # 将发送缓冲区设置为1KB s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1024) s.setblocking(False) # 发送4KB数据,远大于缓冲区容量 data = b"X" * 4096 sent_bytes = s.send(data) print(f"实际发送字节数: {sent_bytes}, 总数据长度: {len(data)}")
内容的提问来源于stack exchange,提问作者NiklasMM
相关产品推荐
相关产品推荐

