【发布时间】:2019-04-22 08:36:51
【问题描述】:
我最终尝试测试一个 UDP 客户端,并希望确保它在通过环回接口发送数据时不正常工作,以避免由此引入的任何细微问题,例如校验和验证 (Bad UDP checksum has no effect: why?)。
但是,即使将数据发送到socket.gethostbyname(socket.gethostname()) 的结果,而不是127.0.0.1,那么根据Wireshark,数据似乎是通过环回接口。
以下程序成功发送和接收b'somedata',并从Wireshark捕获以下内容。
import asyncio
import socket
async def server():
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setblocking(False)
sock.bind(('', 4567))
data = await loop.sock_recv(sock, 512)
print('Received', data)
async def main():
local_ip = socket.gethostbyname(socket.gethostname())
print('Local IP', local_ip) # Outputs 192.168.0.34
asyncio.ensure_future(server())
await asyncio.sleep(0)
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setblocking(False)
sock.connect((local_ip, 4567))
await loop.sock_sendall(sock, b'somedata')
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
如何将数据从本地运行的客户端发送到本地运行的服务器,但避免环回接口并实际将数据发送到网络?
理想的答案将适用于 Linux 和 macOS。
【问题讨论】:
-
请问您要达到什么目的?您是在测试您的代码,还是在测试网络接口?如果你想测试你的代码如何处理坏包,那么也许你应该创建一个在套接字上工作的方法,这样你就可以在单元测试中模拟套接字对象。如果您正在创建生产测试/集成测试/系统测试,那么测试设置应尽可能接近真实(预期)设置。理想情况下,您将拥有一个彼此分离的真实服务器和客户端。也许您可以使用虚拟机或使用两个 USB 转以太网适配器来实现这一点?
-
@wovano 我正在测试我的代码,以及它如何与系统的其余部分交互,避免了模拟引入的假设,所以它更像是一种集成式测试...“那么测试设置应该尽可能接近真实(预期)设置。”同意,看看在没有多台机器/适配器开销的情况下我能走多远。
-
我当然理解您希望避免这种开销。但我认为如果没有系统的其余部分,您无法测试您的应用程序如何与系统的其余部分交互;-) 要实际测试网络接口,您至少需要两个网络接口来保证数据包正在通过线路传输。即使这样,没有交换机的行为也可能与使用交换机的行为有很大不同(例如,由于数据包重新排序、IP 分段等)。例如,Linux 系统可能与 Windows 系统有细微差别。
-
您可以做的是测试正常(预期)行为,以及您能想到的所有错误情况(例如错误的 UDP 校验和)。如果您的应用程序的接口边界选择正确,您可能能够测试大多数情况。您能描述一下您想要测试的什么,即哪些测试用例?这可能有助于提供更好的解决方案。您认为 mocking 会引入哪些假设?
-
“你能描述一下你想测试什么吗”。例如,到达的数据包具有错误的 UDP 校验和如何影响应用程序。它被忽略了吗?照常处理?引发异常? “你认为模拟会引入什么假设”:较低级别的行为实际上就像模拟一样。了解不同的系统有细微的差异,这正是我希望测试使用系统的较低级别行为以确保对其进行较少假设的原因,并且测试通过意味着很有可能应用程序有效。
标签: python python-3.x sockets udp python-asyncio