在Python中模拟慢速网络的简单方法
设想。我有一个客户端与服务器有两个网络连接。一种连接使用手机,另一种连接使用 wlan 连接。
我解决这个问题的方法是让服务器监听两个端口。但是,移动连接应该比 WLAN 连接慢。发送的数据通常只是一行文本。我通过允许移动连接以五秒的间隔发送数据来解决连接速度较慢的问题,而无线局域网连接的间隔为一秒。
但有没有更好的方法来减缓速度呢?也许通过发送较小的数据包,意味着我需要发送更多数据?
关于减慢其中一个连接速度的好方法有什么想法吗?
Orjanp
一个只有一个连接的简单客户端示例。
def client():
import sys, time, socket
port = 11111
host = '127.0.0.1'
buf_size = 1024
try:
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.connect((host, port))
except socket.error, (value, message):
if mySocket:
mySocket.close()
print 'Could not open socket: ' + message
sys.exit(1)
mySocket.send('Hello, server')
data = mySocket.recv(buf_size)
print data
time.sleep(5)
mySocket.close()
client()
一个简单的服务器监听一个端口。
def server():
import sys, os, socket
port = 11111
host = ''
backlog = 5
buf_size = 1024
try:
listening_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
listening_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
listening_socket.bind((host, port))
listening_socket.listen(backlog)
except socket.error, (value, message):
if listening_socket:
listening_socket.close()
print 'Could not open socket: ' + message
sys.exit(1)
while True:
accepted_socket, adress = listening_socket.accept()
data = accepted_socket.recv(buf_size)
if data:
accepted_socket.send('Hello, and goodbye.')
accepted_socket.close()
server()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
除了使用外部工具来模拟您感兴趣的网络类型之外,一种好的方法是使用套接字的替代实现。
这涉及将套接字构造作为函数的参数,而不是导入套接字模块并直接使用它。对于正常操作,您将传入真实的套接字类型,但是当您想要测试各种不利的网络条件时,您可以传入模拟这些条件的实现。例如,您可以创建一个参数化延迟和带宽的套接字类型(未经测试的代码,请注意):
如果您实现其他套接字方法,connect,recv等,您可以用此类的实例替换真实套接字的实例类型。这使得程序的其余部分完全无需了解模拟的任何知识,从而简化了模拟,同时还允许您通过实现模拟它们的新套接字类型来尝试许多不同的网络配置。
这个想法是 Twisted 明确将“协议”(知道如何解释来自网络的字节并生成新字节发送到网络的对象)的概念与“传输”(知道如何获取字节的对象)分开的原因之一。网络并将字节放入其中。这种分离简化了测试,并允许像这样的新颖配置,其中传输提供了对某些其他网络条件(可能难以真实生成)的模拟。
Aside from using an external tool to simulate the kind of network you're interested in, one good approach is to use a substitute implementation of socket.
This involves making the socket construction a parameter to your function, instead of importing the socket module and using it directly. For normal operation, you will pass in the real socket type, but when you want to test various adverse network conditions, you can pass in an implementation that simulates those conditions. For example, you might create a socket type which parameterizes latency and bandwidth (untested code, beware):
If you implement the other socket methods, connect, recv, etc, you can substitute an instance of this class for an instance of the real socket type. This leaves all the rest of your program completely free of any knowledge of your simulation, simplifying it, while also letting you try out many different network configurations by just implementing a new socket type that simulates them.
This idea is one of the reasons Twisted explicitly separates the idea of "protocols" - objects which know how to interpret bytes from the network and generate new bytes to send to the network - from "transports" - objects which know how to get bytes off the network and put bytes onto it. The separation eases testing and allows novel configurations like this one, where a simulation of some other network conditions (which may be difficult to produce for real) is provided by the transport.
冒着无法回答您提出的问题的风险,我会寻找在较低级别执行此操作的软件。
Netlimiter 对 Windows 执行此操作。我认为 BWMeter 和 带宽控制器也可以做到。
pyshaper 是一个类似的 Linux 工具。开源。您也许可以将其导入到您的 Python 程序中。
(要考虑的另一件事是,您可能已经拥有一个能够按照您想要的方式调整流量的路由器。不过,将其添加到您的软件中是一个相当大的依赖项,并且配置可能需要更多工作。)
At the risk of not answering the question you asked, I would look for software that does this at a lower level.
Netlimiter does this for Windows. I think BWMeter and Bandwidth Controller can do it too.
pyshaper is a similar tool for Linux. Open source. You might just be able to import it into your Python program.
(Another thing to consider is that you might already have a router capable of shaping traffic the way you want. That's a pretty big dependency to add to your software, though, and it might be more work to configure.)
那么,网络连接比另一个网络连接“慢”的原因是延迟和/或带宽。因此,如果您想要进行真实的模拟,您需要找到手机连接的带宽及其延迟,并在客户端程序中进行模拟。
但您似乎暗示您发送的数据非常少,因此带宽可能不会真正影响您的连接速度。因此,您可以模拟延迟,这就是您所做的:在发送的每个数据包之间睡眠(延迟)。不过 5 秒似乎很多。
但如果您认为带宽可能相关,那么模拟实际上非常简单:带宽是每秒可以发送的最大字节数,延迟是到达目的地所需的持续时间。
如何做到这一点:有一个全局时间戳“blockedUntil”,表示连接再次空闲以发送数据之前的时间。在程序开始时初始化为 0,因为我们假设它尚未被使用。然后,每次有数据包要发送时,如果“_blockedUntil”小于 now(),请将其设置为 now()。然后通过执行以下操作计算写入虚构“线路”所需的时间: packet.size() / 带宽,这将为您提供持续时间,添加延迟,并将其添加到“blockedUntil”。
现在计算 dt =blockedUntil - now(),将数据包添加到队列中,并添加一个在“dt”中触发的计时器,这将弹出队列中的第一个数据包并发送它。
好了,您已经模拟了带宽和延迟。
编辑:正如有人提到的,也存在丢包的问题。您可以通过丢弃数据包的概率来模拟这一点。 注意:只有在操作来自未连接协议(例如以太网或 UDP)的数据包时,才有可能出现这种情况。例如,对于 TCP 来说,它就不起作用。
Well, what makes a network connection "slower" than another, is due to latency and/or bandwidth. So if you want to have a realistic simulation, you need to find the bandwidth of your mobile phone connection, as well as its latency, and simulate that in your client program.
But you seem to imply that you send very little data, so bandwidth is probably not really going to affect your connection speed. So you can just simulate latency, and that's doing what you do: sleep(latency) between each packet sent. 5 second seems like a lot though.
But if you think bandwidth might be relevant, it's actually quite simple to simulate: bandwidth is the max number of bytes per second that you can send, and latency is the duration it's going to take to get to its destination.
How to do it: have a global timestamp "blockedUntil", representing the time until your connection becomes free again to send data. Initialise to 0 at the beginning of your program, as we assume it's not being used yet. Then, everytime you have a packet to send, If "_blockedUntil" is less than now(), set it to now(). Then calculate the time it would take to write to your fictitious "wire" by doing: packet.size() / bandwidth, that'll get you a time duration, add the latency, and add that to "blockedUntil".
Now compute dt = blockedUntil - now(), add the packet to the queue, and add a timer firing in "dt", which will pop the first packet in the queue, and send it.
There you go, you've simulated bandwidth and latency.
Edit: as someone mentioned there's the question of dropped packets too. You can simulate that by having a probability of dropping packets. Note: This is solely possible when one is manipulating packets from an unconnected protocol such as Ethernet or UDP. In the case of TCP for example, it won't work.
使用 poorconn Python 包可以轻松实现慢速连接的模拟:
例如,在以下代码中,函数
client_socket()
/server_socket()
返回一个客户端/服务器套接字对象,每发送 1024 字节消息就会延迟大约 2 秒。然后,像普通套接字对象一样使用返回的套接字对象。
免责声明:我是 badconn 的主要作者。欢迎反馈。
The simulation of slow connections can be achieved easily with the poorconn Python package:
For example, in the following code, the function
client_socket()
/server_socket()
returns a client/server socket object that delay roughly 2 seconds for sending every 1024 bytes of messages.Then, use the returned socket objects like normal socket objects.
Disclaimer: I'm the main author of poorconn. Feedback is welcome.