2009-12-02 47 views
6

场景。我有一个客户端与服务器的两个网络连接。一个连接使用手机,另一个连接使用wlan连接。模拟python中慢速网络的简单方法

,我已经解决了这一问题的方法是通过让服务器在两个端口上侦听。但是,移动连接应该比wlan连接慢。发送的数据通常只是一行文本。我通过允许移动连接以5秒的间隔发送数据来解决较慢的连接问题,因此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() 
+0

你想减慢什么? – 2009-12-02 15:20:52

+3

相关:http://stackoverflow.com/questions/1094760/network-tools-that-simulate-slow-network-connection – ChristopheD 2009-12-02 15:20:56

+0

这是一个困难的问题..移动连接意味着更长的旅行时间/更多的下降包等 它是没有真正的模拟,只是以较慢的间隔发送它们。 – Shirkrin 2009-12-02 15:39:18

回答

9

除了使用外部工具来模拟一种网络你感兴趣的,一个好的办法是使用插座的替代实现。

这涉及到使套接字构造成为您的函数的一个参数,而不是导入套接字模块并直接使用它。对于正常操作,您将传入真实的套接字类型,但是当您要测试各种不利的网络条件时,可以传入模拟这些条件的实现。例如,您可以创建其参数化延迟和带宽的插座类型(未经测试的代码,谨防):

import time, socket 

class ControllableSocket: 
    def __init__(self, latency, bandwidth): 
     self._latency = latency 
     self._bandwidth = bandwidth 
     self._bytesSent = 0 
     self._timeCreated = time.time() 
     self._socket = socket.socket() 

    def send(self, bytes): 
     now = time.time() 
     connectionDuration = now - self._timeCreated 
     self._bytesSent += len(bytes) 
     # How long should it have taken to send how many bytes we've sent with our 
     # given bandwidth limitation? 
     requiredDuration = self._bytesSent/self._bandwidth 
     time.sleep(max(requiredDuration - connectionDuration, self._latency)) 
     return self._socket.send(bytes) 

如果要实现其他插座方法,连接的recv等,可以替代这个类的一个实例为真实套接字类型的一个实例。这使得程序的其余部分完全没有任何有关仿真的知识,简化了它,同时还让您通过实现模拟它们的新套接字类型来尝试许多不同的网络配置。

这个想法是Twisted明确地将“协议”的概念 - 知道如何从网络中解释字节并生成新字节发送到网络的对象 - 从“传输” - 知道如何从网络中获取字节并将字节放到网络上。这种分离方式简化了测试过程,并且允许像这样的新颖配置,其中一些其他网络条件(实际上可能难以产生)的模拟由运输工具提供。

+0

我会看看这种方法,因为我还需要比移动设备更慢的连接。在这里,我不必担心告诉服务器所有数据都已发送。相当优雅的解决方案。谢谢。 :) – Orjanp 2009-12-03 11:09:57

2

那么,什么使网络连接比其他“慢”,是由于延迟和/或带宽。因此,如果您想要进行逼真的模拟,您需要找到手机连接的带宽以及延迟,并在您的客户端程序中进行模拟。

但你似乎在暗示你发送的数据非常少,因此带宽可能不是真的会影响到你的连接速度。所以你可以模拟延迟,这就是你要做的事情:发送每个数据包之间的睡眠(延迟)。虽然5秒似乎很多。

但是,如果你认为带宽可能是相关的,它实际上很简单的模拟:带宽是你可以发送每秒的最大字节数,延迟是它到达目的地所需的持续时间。

如何做到这一点:有一个全局时间戳“blockedUntil”,表示时间,直到你的连接变得免费再次发送数据。在程序开始时初始化为0,因为我们假设它尚未使用。然后,每次你有一个包发送,如果“_blockedUntil”小于now(),将其设置为now()。然后计算写入虚拟“wire”所需的时间:packet.size()/ bandwidth,这会给你一个持续时间,增加延迟时间,并将其添加到“blockedUntil”。

现在计算DT = blockedUntil - 现在(),该数据包添加到队列中,并在“DT”添加一个计时器射击,这将弹出在队列中的第一个数据包,并将其发送。

你走了,你已经模拟了带宽和延迟。

编辑:有人提到有丢弃的数据包太的问题。您可以通过丢弃数据包的可能性来模拟该数据包。 注意:只有在处理来自未连接协议(例如以太网或UDP)的数据包时,才可能发生这种情况。以TCP为例,它将不起作用。

+1

当您在套接字层上工作时,无法真正导致数据包被丢弃。你可以*模拟**效果**,这是一个额外的延迟(超时+重传),其概率与丢包相同。 – Wim 2009-12-02 16:17:14

+0

那么,如果数据包被丢弃,就不要发送它。我正是这个意思。 – Florian 2009-12-02 16:35:13

+1

TCP不能以这种方式工作。连接是“可靠的”,这意味着如果丢弃携带某些TCP有效负载的IP数据报,数据将被重新发送。从应用程序级别,使用TCP套接字,你不能分辨出什么时候发生,也不能模拟它。丢弃传递给socket.send的一些字节来模拟丢包是一种不正确的数据包丢失模拟。 – 2009-12-02 17:00:56

4

冒着不回答你问的问题,我会寻找软件,在较低的水平上做到这一点。

Netlimiter这是否适用于Windows。我认为BWMeterBandwidth Controller也可以做到。

pyshaper是一个类似Linux的工具。开源。您可能只能将它导入到您的Python程序中。

(另一件需要考虑的事情是,您可能已经拥有了一台能够以您想要的方式改变流量的路由器,不过这对您的软件增加了相当大的依赖性,并且可能需要更多的配置工作。)

+0

我确实考虑过使用这样做的软件。但是,我的机器上或者我的电脑上的虚拟机与电脑本身之间的流量是本地的。所以流量永远不会到达我的电脑外。所以我认为最简单的解决方案是直接在客户端实现它。 – Orjanp 2009-12-03 10:35:13

+0

顺便说一句。感谢pyshaper提示。 – Orjanp 2009-12-03 10:58:56