2009-12-02 9 views
6

Scenario. Ho un client con due connessioni di rete a un server. Una connessione utilizza un telefono cellulare e l'altra utilizza una connessione WLAN.Semplice modo per simulare una rete lenta in python

Il modo in cui l'ho risolto è che il server ascolta due porte. Ma la connessione mobile dovrebbe essere più lenta della connessione wlan. I dati che vengono inviati sono in genere solo una riga di testo. Ho risolto il problema di connessione più lento consentendo alla connessione mobile di inviare dati in un intervallo di cinque secondi, la connessione wlan ha un intervallo di un secondo.

Ma c'è un modo migliore per rallentare? Forse inviando pacchetti più piccoli, il che significa che ho bisogno di inviare più dati?

Qualche idea su un buon modo per rallentare una delle connessioni?

Orjanp

Un semplice esempio cliente con una sola connessione.

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() 

Un semplice server che ascolta una porta.

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

Per cosa stai cercando di rallentare? –

+3

Correlato: http://stackoverflow.com/questions/1094760/network-tools-that-simulate-slow-network-connection – ChristopheD

+0

Questo è un problema difficile .. le connessioni mobili significano tempi di viaggio più lunghi/pacchetti più scartati ecc. nessuna simulazione reale per inviarli a intervalli più lenti. – Shirkrin

risposta

9

Oltre a utilizzare uno strumento esterno per simulare il tipo di rete a cui sei interessato, un buon approccio consiste nell'utilizzare un'implementazione sostitutiva di socket.

Ciò implica che la costruzione del socket è un parametro della funzione, anziché importare il modulo socket e utilizzarlo direttamente. Per il normale funzionamento, passerai nel tipo di socket reale, ma quando vuoi testare varie condizioni di rete avverse, puoi passare a un'implementazione che simuli quelle condizioni. Ad esempio, è possibile creare un tipo di socket che parametrizza latenza e larghezza di banda (codice non testato, attenzione):

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) 

Se si implementano gli altri metodi presa, collegare, recv, ecc, è possibile sostituire un'istanza di questa classe per un'istanza del tipo di socket reale. Questo lascia tutto il resto del tuo programma completamente privo di qualsiasi conoscenza della tua simulazione, semplificandolo, e ti permette anche di provare molte diverse configurazioni di rete semplicemente implementando un nuovo tipo di socket che le simula.

Questa idea è una delle ragioni per cui Twisted separa esplicitamente l'idea di "protocolli" - oggetti che sanno interpretare byte dalla rete e generare nuovi byte da inviare alla rete - da "trasporti" - oggetti che sanno come per estrarre i byte dalla rete e inserirvi dei byte. La separazione facilita i test e consente nuove configurazioni come questa, in cui una simulazione di alcune altre condizioni di rete (che possono essere difficili da produrre per davvero) è fornita dal trasporto.

+0

Darò un'occhiata a questo approccio poiché ho bisogno anche di una connessione ancora più lenta rispetto a quella mobile. Qui non devo preoccuparmi di dire al server che tutti i dati sono stati inviati. Abbastanza una soluzione elegante. Grazie. :) – Orjanp

2

Ebbene, ciò che rende una connessione di rete "più lenta" rispetto ad un altro, è dovuto alla latenza e/o di larghezza di banda. Quindi, se vuoi avere una simulazione realistica, devi trovare la larghezza di banda della tua connessione mobile, oltre alla sua latenza, e simularla nel tuo programma client.

Ma sembra che tu invii pochissimi dati, quindi la larghezza di banda probabilmente non inciderà sulla tua velocità di connessione. Quindi puoi semplicemente simulare la latenza, e questo è ciò che fai: sleep (latenza) tra ogni pacchetto inviato. 5 secondi sembra però molto.

Ma se si pensa che la larghezza di banda potrebbe essere rilevante, è in realtà abbastanza semplice da simulare: la larghezza di banda è il numero massimo di byte al secondo che è possibile inviare e la latenza è la durata che occorrerà per raggiungere la sua destinazione.

Come fare: avere un timestamp globale "blockedUntil", che rappresenta il tempo fino a quando la connessione diventa di nuovo libera per inviare dati. Inizializza a 0 all'inizio del tuo programma, poiché presumiamo che non sia ancora stato utilizzato. Quindi, ogni volta che si invia un pacchetto, Se "_blockedUntil" è minore di now(), impostarlo su now(). Calcola quindi il tempo necessario per scrivere sul tuo "filo" fittizio eseguendo: packet.size()/larghezza di banda, che ti consente di ottenere una durata, aggiungere la latenza e aggiungerla a "blockedUntil".

Ora calcola dt = blockedUntil - now(), aggiungi il pacchetto alla coda e aggiungi un timer che attiva in "dt", che aprirà il primo pacchetto in coda e lo invierà.

Ecco, hai simulato larghezza di banda e latenza.

Edit: come qualcuno ha detto c'è la questione di pacchetti scartati troppo. Puoi simularlo avendo una probabilità di perdere pacchetti. Nota: Ciò è possibile solo quando si manipolano pacchetti da un protocollo non connesso come Ethernet o UDP. Ad esempio, nel caso di TCP, non funzionerà.

+1

Non si può veramente causare la caduta di un pacchetto mentre si lavora sul socket layer. È possibile * modellare ** l'effetto **, che è un ritardo aggiuntivo (timeout + ritrasmettere), con la stessa probabilità di un pacchetto scartato. – Wim

+0

Bene, se il pacchetto viene eliminato, non inviarlo. Ecco cosa intendevo. – Florian

+1

TCP non funziona in questo modo. Le connessioni sono "affidabili", il che significa che se un datagramma IP che trasporta un carico utile TCP viene eliminato, i dati verranno nuovamente inviati. Dal livello dell'applicazione, lavorando con i socket TCP, non è possibile sapere quando ciò accade, né simularlo. L'eliminazione di alcuni byte passati a socket.send per simulare la perdita di pacchetti è una simulazione errata della perdita di pacchetti. –

4

A rischio di non rispondere alla domanda che hai chiesto, vorrei cercare un software che faccia questo a un livello inferiore.

Netlimiter fa questo per Windows. Penso che lo possano fare anche BWMeter e Bandwidth Controller.

pyshaper è uno strumento simile per Linux. Open source. Potresti essere in grado di importarlo nel tuo programma Python.

(Un'altra cosa da considerare è che si potrebbe già avere un router in grado di modellare il traffico nel modo desiderato. Questo è un abbastanza grande dipendenza da aggiungere al vostro software, però, e potrebbe essere più lavoro da configurare.)

+0

Ho preso in considerazione l'utilizzo di software che ha fatto questo. Ma il traffico è locale sulla mia macchina, o tra una macchina virtuale sul mio computer e il computer stesso. Quindi il traffico non arriva mai fuori dal mio computer. Quindi ho pensato che la soluzione più semplice fosse implementarla direttamente nel client. – Orjanp

+0

Btw. Grazie per il suggerimento di Pyshaper. – Orjanp

Problemi correlati