Como faço para atrasar o tráfego tcp em um soquete?

2

Eu gostaria de testar as interações entre um programa cliente e um programa de servidor para condições de corrida. Eles se conectam através do tcp. O cliente bloqueia chamadas para o servidor em vários encadeamentos (uma conexão tcp ao servidor por encadeamento). Eu gostaria de testar a condição de corrida em que uma chamada de bloqueio termina antes da outra.

Para fazer isso, eu esperava atrasar as conexões tcp por quantidades diferentes (para que eu não precise reescrever explicitamente o cliente ou o servidor).

Eu esperava fazer algo assim:

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

em que $pin é a porta à qual o cliente se conecta, $delay é o número de segundos a atrasar e $pout é a porta que o servidor atende. E delaycat é um programa imaginário que retarda o fluxo de entrada em n segundos.

Existe algum programa existente que faz o que eu quero? Ou devo escrever delaycat ?

Editar: observe que um atraso no sistema não seria ideal, pois eu gostaria de atrasar os soquetes individuais em quantidades diferentes, se possível.

    
por Nicholas Grasevski 29.07.2014 / 04:01

2 respostas

2

Eu não consegui encontrar nada por aí, então escrevi um script python para fazer isso (isso provavelmente é um bug):

#!/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()
    
por 04.08.2014 / 08:18
1

Em uma máquina linux você pode usar o tc com o Netem .

Por exemplo, o comando tc qdisc add dev eth0 root netem delay 100ms atrasará os pacotes de saída all em 100 milissegundos. Para atrasar os pacotes recebidos, você pode usar o ifb - Bloco Funcional Intermediário

    
por 06.08.2014 / 09:05