Gostaria de testar as interações entre um programa cliente e um programa servidor para condições de corrida. Eles se conectam via tcp. O cliente bloqueia chamadas para o servidor em vários threads (uma conexão TCP com o servidor por thread). 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 em quantidades diferentes (para não precisar reescrever explicitamente o cliente ou o servidor).
Eu esperava fazer algo assim:
socat tcp-listen:$pin system:"delaycat $delay |socat - 'tcp:localhost:$pout'"
onde $pin
é a porta à qual o cliente se conecta, $delay
é o número de segundos de atraso e $pout
é a porta na qual o servidor escuta. E delaycat
é um programa imaginário que atrasa 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 em todo o sistema não seria realmente o ideal, pois eu gostaria de atrasar os soquetes individuais em quantidades diferentes, se possível.
Responder1
Não consegui encontrar nada por aí, então escrevi um script python para fazer isso (provavelmente tem bugs):
#!/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()
Responder2
Em uma máquina Linux você pode usar tc comNetem.
Por exemplo, o comando tc qdisc add dev eth0 root netem delay 100ms
irá atrasartodospacotes de saída em 100 milissegundos. Para atrasar pacotes recebidos você pode usar oifb - Bloco Funcional Intermediário