¿Cómo retraso el tráfico TCP en un socket?

¿Cómo retraso el tráfico TCP en un socket?

Me gustaría probar las interacciones entre un programa cliente y un programa servidor para las condiciones de carrera. Se conectan entre sí mediante tcp. El cliente bloquea las llamadas al servidor en varios subprocesos (una conexión tcp al servidor por subproceso). Me gustaría probar la condición de carrera en la que una llamada de bloqueo termina antes que la otra.

Para hacer esto, esperaba retrasar las conexiones tcp en diferentes cantidades (para no tener que reescribir explícitamente ni el cliente ni el servidor).

Esperaba hacer algo como esto:

socat tcp-listen:$pin system:"delaycat $delay |socat - 'tcp:localhost:$pout'"

¿Dónde $pinestá el puerto al que se conecta el cliente, $delayel número de segundos de retraso y $poutel puerto en el que escucha el servidor? Y delaycates un programa imaginario que retrasa el flujo de entrada n segundos.

¿Existe algún programa que haga lo que quiero? ¿O debería escribir delaycat?

Editar:tenga en cuenta que un retraso en todo el sistema no sería realmente ideal, ya que me gustaría retrasar los sockets individuales en cantidades diferentes si es posible.

Respuesta1

No pude encontrar nada por ahí, así que escribí un script en Python para hacer esto (probablemente tenga errores):

#!/usr/bin/env python26
"""Add latency to a tcp connection"""
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from functools import partial

from twisted.internet.reactor import (
    listenTCP, connectTCP, callLater, run
)
from twisted.internet.protocol import (
    ServerFactory, ReconnectingClientFactory, Protocol
)


class ConnectionToServer(Protocol):
    def __init__(self, connection_from_client, delay_to_client):
        self._delay_to_client = delay_to_client
        self._connection_from_client = connection_from_client

    def connectionMade(self):
        self._connection_from_client.connection_to_server = self
        if self._connection_from_client.buffer_from_client:
            self.transport.write(
                self._connection_from_client.buffer_from_client
            )

    def dataReceived(self, data):
        callLater(
            self._delay_to_client,
            self._connection_from_client.transport.write, data
        )

    def connectionLost(self, reason):
        callLater(
            self._delay_to_client,
            self._connection_from_client.transport.loseConnection
        )


class ConnectionFromClient(Protocol):
    def __init__(self, server_host, server_port, delay_to_client, delay_to_server):
        self._delay_to_server = delay_to_server
        self.connection_to_server = None
        self.buffer_from_client = ''
        server_connection_factory = ReconnectingClientFactory()
        server_connection_factory.protocol = partial(
            ConnectionToServer, self, delay_to_client
        )
        self._server_connector = connectTCP(
            server_host, server_port, server_connection_factory
        )

    def dataReceived(self, data):
        callLater(self._delay_to_server, self._write, data)

    def connectionLost(self, reason):
        callLater(
            self._delay_to_server, self._server_connector.disconnect
        )

    def _write(self, data):
        if self.connection_to_server:
            self.connection_to_server.transport.write(data)
        else:
            self.buffer_from_client += data


def main():
    """Add latency to a tcp connection"""
    parser = ArgumentParser(
        description=main.__doc__,
        formatter_class=ArgumentDefaultsHelpFormatter
    )
    parser.add_argument(
        'client_port', type=int, help='client connects to this port'
    )
    parser.add_argument(
        'server_port', type=int, help='server listens on this port'
    )
    parser.add_argument(
        '-t', '--server-host', default='localhost',
        help='server is running on this host'
    )
    parser.add_argument(
        '-c', '--delay-to-client', default=0, type=float,
        help='messages to client are delayed by this many seconds'
    )
    parser.add_argument(
        '-s', '--delay-to-server', default=0, type=float,
        help='messages to server are delayed by this many seconds'
    )
    args = parser.parse_args()
    client_connection_factory = ServerFactory()
    client_connection_factory.protocol = partial(
        ConnectionFromClient, args.server_host, args.server_port,
        args.delay_to_client, args.delay_to_server
    )
    listenTCP(args.client_port, client_connection_factory)
    run()
if __name__ == '__main__':
    main()

Respuesta2

En una máquina Linux puedes usar tc connetem.

Por ejemplo, el comando tc qdisc add dev eth0 root netem delay 100msretrasarátodopaquetes salientes en 100 milisegundos. Para retrasar los paquetes entrantes, puede utilizar elifb - Bloque funcional intermedio

información relacionada