[ACCEPTED]-Simple way to simulate a slow network in python-network-programming

Accepted answer
Score: 13

Aside from using an external tool to simulate 32 the kind of network you're interested in, one 31 good approach is to use a substitute implementation 30 of socket.

This involves making the socket 29 construction a parameter to your function, instead 28 of importing the socket module and using 27 it directly. For normal operation, you 26 will pass in the real socket type, but when 25 you want to test various adverse network 24 conditions, you can pass in an implementation 23 that simulates those conditions. For example, you 22 might create a socket type which parameterizes 21 latency and bandwidth (untested code, beware):

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)

If 20 you implement the other socket methods, connect, recv, etc, you 19 can substitute an instance of this class 18 for an instance of the real socket type. This 17 leaves all the rest of your program completely 16 free of any knowledge of your simulation, simplifying 15 it, while also letting you try out many 14 different network configurations by just 13 implementing a new socket type that simulates 12 them.

This idea is one of the reasons Twisted 11 explicitly separates the idea of "protocols" - objects 10 which know how to interpret bytes from the 9 network and generate new bytes to send to 8 the network - from "transports" - objects 7 which know how to get bytes off the network 6 and put bytes onto it. The separation eases 5 testing and allows novel configurations 4 like this one, where a simulation of some 3 other network conditions (which may be difficult 2 to produce for real) is provided by the 1 transport.

Score: 4

At the risk of not answering the question 10 you asked, I would look for software that 9 does this at a lower level.

Netlimiter does this for 8 Windows. I think BWMeter and Bandwidth Controller can do it too.

pyshaper is 7 a similar tool for Linux. Open source. You 6 might just be able to import it into your 5 Python program.

(Another thing to consider 4 is that you might already have a router 3 capable of shaping traffic the way you want. That's 2 a pretty big dependency to add to your software, though, and 1 it might be more work to configure.)

Score: 2

Well, what makes a network connection "slower" than 40 another, is due to latency and/or bandwidth. So 39 if you want to have a realistic simulation, you 38 need to find the bandwidth of your mobile 37 phone connection, as well as its latency, and 36 simulate that in your client program.

But 35 you seem to imply that you send very little 34 data, so bandwidth is probably not really 33 going to affect your connection speed. So 32 you can just simulate latency, and that's 31 doing what you do: sleep(latency) between 30 each packet sent. 5 second seems like a 29 lot though.

But if you think bandwidth might 28 be relevant, it's actually quite simple 27 to simulate: bandwidth is the max number 26 of bytes per second that you can send, and 25 latency is the duration it's going to take 24 to get to its destination.

How to do it: have 23 a global timestamp "blockedUntil", representing 22 the time until your connection becomes free 21 again to send data. Initialise to 0 at the 20 beginning of your program, as we assume 19 it's not being used yet. Then, everytime 18 you have a packet to send, If "_blockedUntil" is 17 less than now(), set it to now(). Then calculate 16 the time it would take to write to your 15 fictitious "wire" by doing: packet.size() / bandwidth, that'll 14 get you a time duration, add the latency, and 13 add that to "blockedUntil".

Now compute dt 12 = blockedUntil - now(), add the packet to 11 the queue, and add a timer firing in "dt", which 10 will pop the first packet in the queue, and 9 send it.

There you go, you've simulated bandwidth 8 and latency.

Edit: as someone mentioned there's 7 the question of dropped packets too. You 6 can simulate that by having a probability 5 of dropping packets. Note: This is solely possible 4 when one is manipulating packets from an 3 unconnected protocol such as Ethernet or 2 UDP. In the case of TCP for example, it 1 won't work.

Score: 2

The simulation of slow connections can be 8 achieved easily with the poorconn Python package:

pip install poorconn

For 7 example, in the following code, the function 6 client_socket()/server_socket() returns a client/server socket object 5 that delay roughly 2 seconds for sending 4 every 1024 bytes of messages.

from socket import socket
from poorconn import delay_before_sending, make_socket_patchable

def client_socket():
    s = socket()
    s = make_socket_patchable(s)
    delay_before_sending(s, 2, 1024)
    return s

def server_socket():
    s = socket()
    s = make_socket_patchable(s)
    delay_before_sending_upon_acceptance(s, 2, 1024)
    return s

Then, use the 3 returned socket objects like normal socket 2 objects.

Disclaimer: I'm the main author 1 of poorconn. Feedback is welcome.

More Related questions