2009-12-02 18 views
6

Escenario. Tengo un cliente con dos conexiones de red a un servidor. Una conexión usa un teléfono móvil y la otra usa una conexión wlan.Forma simple de simular una red lenta en python

La forma en que he resuelto esto es haciendo que el servidor escuche en dos puertos. Pero, la conexión móvil debe ser más lenta que la conexión wlan. Los datos que se envían generalmente son solo una línea de texto. He resuelto el problema de conexión más lenta al permitir que la conexión móvil envíe datos en un intervalo de cinco segundos, la conexión wlan tiene un intervalo de un segundo.

¿Pero hay una mejor manera de hacer la ralentización? ¿Quizás enviando paquetes más pequeños, lo que significa que necesito enviar más datos?

¿Alguna idea sobre una buena forma de ralentizar una de las conexiones?

Orjanp

Un ejemplo simple cliente con una sola conexión.

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 servidor simple que escucha un puerto.

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

¿Qué estás tratando de reducir la velocidad? –

+3

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

+0

Este es un problema difícil ... las conexiones móviles significan tiempos de viaje más largos/más paquetes caídos, etc. Es no hay simulación real para simplemente enviarlos a intervalos más lentos. – Shirkrin

Respuesta

9

Además de utilizar una herramienta externa para simular el tipo de red que le interesa, un buen enfoque es utilizar una implementación sustitutiva de socket.

Esto implica hacer de la construcción del socket un parámetro para su función, en lugar de importar el módulo de socket y usarlo directamente. Para una operación normal, pasará el tipo de socket real, pero cuando quiera probar varias condiciones de red adversas, puede pasar una implementación que simule esas condiciones. Por ejemplo, puede crear un tipo de socket, que parametriza latencia y ancho de banda (código no probado, tenga cuidado):

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) 

Si implementa los otros métodos de socket, conecta, recv, etc, se puede sustituir una instancia de esta clase para una instancia del tipo de socket real. Esto deja al resto de tu programa completamente libre de cualquier conocimiento de tu simulación, simplificándolo, al mismo tiempo que te permite probar muchas configuraciones de red diferentes simplemente implementando un nuevo tipo de socket que las simule.

Esta idea es una de las razones Twisted separa explícitamente la idea de "protocolos" - objetos que saben cómo interpretar bytes de la red y generar nuevos bytes para enviar a la red - desde "transportes" - objetos que saben cómo para obtener bytes de la red y poner bytes en ella. La separación facilita las pruebas y permite configuraciones novedosas como esta, donde el transporte proporciona una simulación de algunas otras condiciones de la red (que pueden ser difíciles de producir de verdad).

+0

Echaré un vistazo a este enfoque ya que también necesito una conexión aún más lenta que la móvil. Aquí no tengo que preocuparme de decirle al servidor que se han enviado todos los datos. Una solución bastante elegante. Gracias. :) – Orjanp

2

Bueno, lo que hace que una conexión de red "más lento" que otro, se debe a la latencia y/o ancho de banda. Entonces, si desea tener una simulación realista, necesita encontrar el ancho de banda de su conexión de teléfono móvil, así como su latencia, y simular eso en su programa de cliente.

Pero parece implicar que envía muy pocos datos, por lo que el ancho de banda probablemente no afectará la velocidad de su conexión. Entonces puede simular latencia, y eso es hacer lo que hace: dormir (latencia) entre cada paquete enviado. 5 segundos parece mucho.

Pero si crees que el ancho de banda puede ser relevante, en realidad es bastante simple de simular: el ancho de banda es el número máximo de bytes por segundo que puedes enviar y la latencia es la duración que tardará en llegar a destino.

Cómo hacerlo: tener una marca de tiempo global "blockedUntil", que representa el tiempo hasta que su conexión se vuelva a liberar para enviar datos. Inicialice a 0 al comienzo de su programa, ya que suponemos que aún no se está utilizando. Luego, cada vez que tenga un paquete para enviar, si "_blockedUntil" es menor que ahora(), configúrelo en now(). Luego calcule el tiempo que llevaría escribir en su "cable" ficticio haciendo: packet.size()/bandwidth, que le dará un tiempo de duración, agregará la latencia y lo agregará a "blockedUntil".

Ahora calcule dt = blockedUntil - now(), agregue el paquete a la cola y agregue un temporizador que se active en "dt", que insertará el primer paquete en la cola y lo enviará.

Ahí tienes, has simulado ancho de banda y latencia.

Editar: como alguien mencionó que existe la cuestión de los paquetes caídos también. Puede simular eso teniendo una probabilidad de descartar paquetes. Nota: Esto solo es posible cuando se manipulan paquetes de un protocolo no conectado como Ethernet o UDP. En el caso de TCP, por ejemplo, no funcionará.

+1

Realmente no puede causar la caída de un paquete cuando está trabajando en la capa de socket. Usted * puede * modelar el ** efecto **, que es un retraso adicional (tiempo de espera + retransmisión), con la misma probabilidad que la de un paquete descartado. – Wim

+0

Bueno, si el paquete se cae, simplemente no lo envíe. A eso me refería. – Florian

+1

TCP no funciona de esa manera. Las conexiones son "confiables", lo que significa que si un datagrama IP que transporta alguna carga TCP se elimina, los datos serán reenviados. Desde el nivel de aplicación, trabajando con sockets TCP, no se puede saber cuándo sucede esto, ni simularlo. Dejar caer algunos bytes que se pasan a socket.send para simular la pérdida de paquetes es una simulación incorrecta de la pérdida de paquetes. –

4

A riesgo de no responder la pregunta que me hizo, buscaría un software que haga esto en un nivel inferior.

Netlimiter hace esto para Windows. Creo que BWMeter y Bandwidth Controller pueden hacerlo también.

pyshaper es una herramienta similar para Linux. Fuente abierta. Es posible que solo pueda importarlo a su programa Python.

(Otra cosa a considerar es que es posible que ya tiene un router capaz de controlar el tráfico de la manera deseada. Eso es algo muy importante dependencia de añadir a su software, sin embargo, y puede ser más trabajo para configurar.)

+0

Consideré usar un software que hizo esto. Pero el tráfico es local en mi máquina, o entre una máquina virtual de mi computadora y la computadora misma. Entonces, el tráfico nunca llega a mi computadora. Así que pensé que la solución más simple era implementarlo directamente en el cliente. – Orjanp

+0

Por cierto. Gracias por la punta de Pyshaper. – Orjanp

Cuestiones relacionadas