network/tcp_echo_server/resources/tcp_multiple_client.py

1 import socket
2 import time
3 import json
4 import random
5 import optparse
6 from threading import Thread, Event
7 
8 
9 # This script randomly opens and closes TCP server clients
10 # When the client socket is opened, it random blasts data
11 # This script can be very abusive to the TCP server, hence it's a greate test
12 
13 
14 
15 
16 
17 def main(options):
18  udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
19  udp_socket.bind(('', options.port))
20 
21  print "Discovering device with UUID:%s via UDP broadcast ..." % options.uuid
22  while(1):
23  recv_data, addr = udp_socket.recvfrom(2048)
24  if recv_data != None:
25  try:
26  info = json.loads(recv_data)
27  if info['uuid'] != options.uuid:
28  continue
29 
30  server_address = (info['ip'], info['remote_terminal_port'])
31  print "Discovered device TCP server at:%s:%d" % server_address
32  break
33 
34  except:
35  pass
36 
37  print "Starting %d TCP clients" % options.num_clients
38 
39  running = Event()
40  running.set()
41 
42  for client in range(0, options.num_clients):
43  try:
44  Thread(name='Client:%d' % client,
45  target=tcp_client_handler,
46  args=(running, options, server_address, client)).start()
47  except Exception as e:
48  print "Exception: %s" % e
49  raise
50 
51  try:
52  while True:
53  time.sleep(10)
54  except:
55  print '\n\n\n'
56  print '*'*30
57  print "Exiting app ...\n\n\n"
58  pass
59 
60  running.clear()
61 
62 
63 def print_client_log(client_id, msg):
64  m = "[Client:%d] " % client_id
65  print m + msg
66 
67 
68 def tcp_client_handler(running, options, server_address, client_id):
69  while running.is_set():
70  close_after_waiting = bool(random.getrandbits(1))
71  # Randomly decide if we should read back the RX data
72  should_rx_data = bool(random.getrandbits(1))
73  # Randomly decide the amount of time we should sleep
74  # before restart the loop
75  sleep_time = random.uniform(options.wait_time_min, options.wait_time_max)
76  # Randomly decide the size of the TX message
77  message_length = int(random.uniform(options.data_size_min, options.data_size_max))
78  # Randomly decide the size of the TX chunk size
79  chunk_length = int(random.uniform(options.data_chunk_size_min, max(options.data_chunk_size_max,message_length)))
80 
81  s = socket.socket()
82  print_client_log(client_id, "Connecting to %s:%d" % server_address)
83  s.connect(server_address)
84  print_client_log(client_id, "Connected.")
85 
86  msg = "Loop info:\n"
87  msg += " Message length: %d bytes\n" % message_length
88  msg += " Chunk length: %d bytes\n" % chunk_length
89  msg += " Sleep time: %1.3fs\n" % sleep_time
90  msg += " Read RX data: %s\n" % ("Yes" if should_rx_data else "No")
91  msg += " Close after waiting: %s" % ("Yes" if close_after_waiting else "No")
92  print_client_log(client_id, msg)
93 
94 
95  tx_msg = '%d' % client_id
96  tx_msg *= message_length
97 
98  while len(tx_msg) > 0:
99  chunk = tx_msg[:chunk_length]
100  tx_msg = tx_msg[chunk_length:]
101  while len(chunk) > 0:
102  n = s.send(chunk)
103  chunk = chunk[n:]
104 
105  if should_rx_data:
106  while message_length > 0:
107  rx_msg = s.recv(min(message_length, 4096))
108  if rx_msg == '':
109  print_client_log(client_id, "Server closed connection")
110  break
111  message_length -= len(rx_msg)
112  print_client_log(client_id, "RX data remaining: %d" % message_length)
113 
114 
115  if close_after_waiting:
116  time.sleep(sleep_time)
117 
118  s.close()
119  print_client_log(client_id, "Connection closed")
120 
121  if not close_after_waiting:
122  time.sleep(sleep_time)
123 
124 
125 
126 
127 if __name__ == "__main__":
128  cli = optparse.OptionParser(description='This script randomly opens and closes TCP server clients.\n' +
129  'When the client socket is opened, it random blasts data')
130 
131  cli.add_option('--uuid', '-u',
132  default=None,
133  help="required: Device's UUID, the device running the example TCP echo server app")
134 
135  cli.add_option('--port', '-p',
136  default=55555,
137  type='int',
138  help='UDP port device broadcasts its connection info [default: %default]')
139 
140  cli.add_option('--wait_time_min',
141  default=0.1,
142  type='float',
143  help='Lower limit on range in seconds to wait before restarting TCP client loop [default: %default]')
144 
145  cli.add_option('--wait_time_max',
146  default=5.0,
147  type='float',
148  help='Upper limit on range in seconds to wait before restarting TCP client loop [default: %default]')
149 
150  cli.add_option('--data_size_min',
151  default=50,
152  type='int',
153  help='Lower limit on rangein bytes of client TX message [default: %default]')
154  cli.add_option('--data_size_max',
155  default=5000,
156  type='int',
157  help='Upper limit on range in bytes of client TX message [default: %default]')
158 
159  cli.add_option('--data_chunk_size_min',
160  default=50,
161  type='int',
162  help='Lower limit on range in bytes to chunk the TX message (this cause the TCP data to be sent in multiple packets) [default: %default]')
163 
164  cli.add_option('--data_chunk_size_max',
165  default=5000,
166  type='int',
167  help='Upper limit on range in bytes to chunk the TX message (this cause the TCP data to be sent in multiple packets) [default: %default]')
168 
169  cli.add_option('--num_clients', '-n',
170  default=4,
171  type='int',
172  help='Maximum number of connected clients [default: %default]')
173 
174  options, _ = cli.parse_args()
175 
176  if options.uuid == None:
177  cli.print_help()
178  raise Exception("Must supply '--uuid' argument")
179 
180  main(options)
181