def send_observe_request(self, server_ip, server_port, app_ip, app_port, endpoint_name, object_id, observe, \ payload=None, object_inst_id=None, res_id=None, \ res_inst_id=None, content_type=None, token=None, client_port=5683): server_ip_port = server_ip + ":" + str(server_port) path = "rd" if payload is not None and endpoint_name is None: pass elif endpoint_name is not None: path += "/" + endpoint_name payload = dumps({"app_ip" : app_ip, "app_port" : app_port}) content_type = "application/json" if object_id is not None: path += "/" + str(object_id) if object_inst_id is not None: path += "/" + str(object_inst_id) if res_id is not None: path += "/" + str(res_id) if res_inst_id is not None: path += "/" + str(res_inst_id) else: message = "Object ID is missing" self.logger.error(message) return message else: message = "Endpoint is missing" self.logger.error(message) return message try: client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.get(path, data=payload, observe=observe, content_type=content_type, token=token) except: return None return result
def discover_resources(self, server_ip, server_port, payload=None, endpoint_name=None, object_id=None, object_inst_id=None, res_id=None, res_inst_id=None, client_port=5683): server_ip_port = server_ip + ":" + str(server_port) query = "?method=discover" content_type = None path = "rd" if payload is not None: """ ".well-known/core" is a payload """ content_type = "text/plain" else: if (endpoint_name or object_id) is not None: path += "/" + endpoint_name + "/" + str(object_id) if object_inst_id is None and res_id is not None: object_inst_id = 0 path += "/" + str(object_inst_id) elif object_inst_id is not None: path += "/" + str(object_inst_id) if res_id is not None: path += "/" + str(res_id) if res_inst_id is None: res_inst_id = 0 path += "/" + str(res_inst_id) else: self.logger.error("Endpoint Name and object_id should be specified") return path += query client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.get(path, data=payload, timeout=10000, content_type=content_type) return result
def read_resource(self, server_ip, server_port, endpoint_name, object_id, res_id, object_inst_id=None, \ res_inst_id=None, client_port=5683): query = "?method=read" server_ip_port = server_ip + ":" + str(server_port) path = "rd/" + endpoint_name + "/" + str(object_id) if object_inst_id is not None: path += "/" + str(object_inst_id) else: path +="/0" if res_id is not None: path += "/" + str(res_id) if res_inst_id is not None: path += "/" +str(res_inst_id) else: path += "/0" payload = None #content_type = "application/json" path += query client = CoapClient("coap://" + server_ip_port, client_port=client_port) #result = client.get(path, data=payload, content_type=content_type) result = client.get(path, data=payload, timeout=10000) return result
def send_notification(self, server_ip, server_port, token_id, payload, content_type=None, time_elapse=1, client_ip=None, client_port=None): path = "rd?" query = "method=notify" path += query server_ip_port = server_ip + ":" + str(server_port) client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.post(path, dumps(payload), timeout=10000, content_type=content_type, token=token_id, observe=time_elapse) return result
def client_registration(self, server_ip, server_port, query, payload, path="rd?", content_type="application/link-format", client_port=5683): server_ip_port = server_ip + ":" + str(server_port) client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.post(str(path+query), payload, timeout=10000, content_type=content_type) return client, result
def client_registration_update(self, server_ip, server_port, path, query, payload, \ client_port=5683, client=None): server_ip_port = server_ip + ":" + str(server_port) path_query = str(path) + "?" + query payload = payload if client is None: client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.put(path_query, payload, timeout=10000) return result
def __init__(self, uri, client_port=None, *args, **kw): self.client = CoapClient(uri, client_port) self.logger.debug("CoapClient created with uri %s", uri) self.__serializer = JsonSerializer() self.methodmappers = { "create": self._send_create, "notify": self._send_notify, "update": self._send_update, "delete": self._send_delete, "retrieve": self._send_retrieve }
def execute_resource(self, server_ip, server_port, endpoint_name, object_id, object_inst_id, \ res_id, res_inst_id=None, payload=None, client_port=5683): server_ip_port = server_ip + ":" + str(server_port) path = "rd" query = "?method=execute" if (endpoint_name and object_id and object_inst_id and res_id) is not None: path += "/" + endpoint_name + "/" + str(object_id) + "/" + str(object_inst_id) + \ "/" + str(res_id) if res_inst_id is not None: path += "/" + str(res_inst_id) path += query client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.post(path, payload, timeout=10000) return result
def create_object_instance(self, server_ip, server_port, endpoint_name, object_id, \ payload, content_type, object_inst_id=None, client_port=5683): server_ip_port = server_ip + ":" + str(server_port) query = "?method=create" path = "rd" if (endpoint_name and object_id) is not None: path += "/" + endpoint_name + "/" + str(object_id) if object_inst_id is not None: path += "/" + str(object_inst_id) else: self.logger.error("Endpoint Name and object_id should be specified") return path += query client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.post(path, payload, timeout=10000, content_type=content_type)
def write_attributes(self, server_ip, server_port, endpoint_name, object_id, payload, content_type, object_inst_id=None, res_id=None, res_inst_id=None, client_port=5683): server_ip_port = server_ip + ":" + str(server_port) query = "?method=write_attributes" path = "rd/" + endpoint_name + "/" + str(object_id) if object_inst_id is not None: path += "/" + str(object_inst_id) if res_id is not None: path += "/" + str(res_id) if res_inst_id is None: res_inst_id = 0 path += "/" + str(res_inst_id) path += query client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.put(path, payload, timeout=10000, content_type=content_type) return result
def reset(filename="data"): """Clear the file content""" f = open(filename, 'w') f.write('') f.close() """Delete the old application and create a new one""" client = CoapClient(IP) client.delete('m2m/applications/apptest') client.post('m2m/applications', '{"application": {"appId":"apptest"}}', content_type='application/json') client.post('m2m/applications/apptest/containers', '{"container": {"id":"cont1"}}', content_type='application/json')
def measure_get(i): if (i + 1) % 50 == 0: print "%s requests processed" % (i + 1) client = CoapClient(IP, client_port=i + 10000) t = timeit(lambda: repeat_get(client), number=1) t_list.append(t) avg = 0 for tt in t_list: avg += tt avg = avg / len(t_list) f = open(filename, 'a') f.write('%s %s\n' % (str(t), avg)) f.close()
def __init__(self, uri, client_port=None, scl_base=None, use_xml=False, keyfile=None, certfile=None, block_size_exponent=10, *args, **kw): """Initializes XIXCoap and its underlying CoapClient :param uri:URI referencing the server this clients is trying to reach. Can contain SCHEME://IP:PORT :param client_port: Port used by the client when sending requests :param scl_base: Default basename to prefix an SCL resource path :param use_xml: Binary parameter swapping between content types of xml and json """ self.client = CoapClient(uri, client_port or 25682, keyfile=keyfile, certfile=certfile, block_size_exponent=block_size_exponent) self.scl_base = scl_base self.logger.debug("CoapClient created with uri %s", uri) if use_xml: from openmtc_etsi.serializer.xml import XMLSerializer as Serializer self.content_type = "application/xml" else: from openmtc_etsi.serializer.json import JsonSerializer as Serializer self.content_type = "application/json" self.__serializer = Serializer() self.methodmappers = { "create": self._send_create, "notify": self._send_notify, "update": self._send_update, "delete": self._send_delete, "retrieve": self._send_retrieve }
def _get_client(self, parsed_url): coaps = parsed_url.scheme[-1].lower() == "s" port = parsed_url.port # or (coaps and 443 or 80) host = parsed_url.hostname # path = parsed_url.path key = (host, port, coaps) try: return self._clients[key] except KeyError: # TODO: make connection_timeout and concurrency configurable client = self._clients[key] = CoapClient(parsed_url.scheme + "://" + parsed_url.netloc, self.clientport) return client
def write_resource(self, server_ip, server_port, endpoint_name, object_id, \ payload, content_type, object_inst_id=None, res_id=None, \ res_inst_id=None, client_port=5683): query = "?method=write" server_ip_port = server_ip + ":" + str(server_port) path = "rd/" + endpoint_name + "/" + str(object_id) if object_inst_id is not None: path += "/" + str(object_inst_id) else: path +="/0" if res_id is not None: path += "/" + str(res_id) if res_inst_id is not None: path += "/" +str(res_inst_id) else: path += "/0" path += query client = CoapClient("coap://" + server_ip_port, client_port=client_port) result = client.put(path, payload, timeout=10000, content_type=content_type)
#Coap Client example #PYTHONPATH=../:../../src:../../../futile/src python SimpleTestClient.py from coap import CoapClient import logging import time logging.basicConfig(level=logging.INFO) logger = logging.getLogger("ContentInstances_Test") client = CoapClient("coap://localhost:4000") results = 0 def resultPrinter(result): global results results += 1 # print "got result ", result # print result errors = 0 def errorPrinter(error): global errors errors += 1 # print "got error", error # print error
if "://" not in uri: uri = "coap://" + uri info = urlparse(uri) if info.scheme and info.scheme not in ("coap", "coaps"): raise ValueError("Unhandled URI scheme: %s" % (info.scheme, )) if not info.netloc: raise ValueError("No host specified") path = info.path.split("/", 1)[-1] or "" if info.query: path += "?%s" % (info.query, ) uri = "coap://%s" % (info.netloc, ) except Exception as e: logger.error("Malformed URI: %s", e) sys.exit(2) client = CoapClient(uri) _TransactionTypeMap = {0: 'CON', 1: 'NON', 2: 'ACK', 3: 'RST'} _transaction_type_str = lambda t: '%s (%s)' % (_TransactionTypeMap[t], t) _CodeMap = {} _code_str = lambda c: '%s (%s)' % (_CodeMap[c], c) _code_list = [ '2.01 Created', '2.02 Deleted', '2.03 Valid', '2.04 Changed', '2.05 Content', '4.00 Bad Request', '4.01 Unauthorized', '4.02 Bad Option', '4.03 Forbidden', '4.04 Not Found', '4.05 Method Not Allowed', '4.06 Not Acceptable', '4.12 Precondition Failed', '4.13 Request Entity Too Large', '4.15 Unsupported Content-Format',
class XIXCoap(LoggerMixin): def __init__(self, uri, client_port=None, *args, **kw): self.client = CoapClient(uri, client_port) self.logger.debug("CoapClient created with uri %s", uri) self.__serializer = JsonSerializer() self.methodmappers = { "create": self._send_create, "notify": self._send_notify, "update": self._send_update, "delete": self._send_delete, "retrieve": self._send_retrieve } def send_request_indication(self, request_indication): path = request_indication.path if path.startswith('/'): path = path[1:] mapper = self.methodmappers[request_indication.method] return mapper(request_indication, path) def _raise_error(self, method, response): try: status_code = _coap2etsi[response.code] except KeyError: self.logger.warning("Failed to map coap response code: %s", response.code) status_code = openmtc.exc.STATUS_INTERNAL_SERVER_ERROR raise ErrorResponseConfirmation( statusCode=status_code, primitiveType=method, errorInfo=response.payload or "<no further information available>") def _send_create(self, request_indication, path): data = self.__serializer.encode_values(request_indication.typename, request_indication.resource) resp = self.client.post(path, data, content_type="application/json") if resp.code >= 100: self._raise_error("create", resp) return CreateResponseConfirmation(resp.payload) def _send_notify(self, request_indication, path): data = self.__serializer.encode_values(request_indication.typename, request_indication.resource) resp = self.client.post(path, data, content_type="application/json") if resp.code >= 100: self._raise_error("notify", resp) return NotifyResponseConfirmation() def _send_update(self, request_indication, path): data = self.__serializer.encode_values(request_indication.typename, request_indication.resource) resp = self.client.put(path, data, content_type="application/json") if resp.code >= 100: self._raise_error("create", resp) return UpdateResponseConfirmation() def _send_retrieve(self, request_indication, path): resp = self.client.get(path) if resp.code >= 100: self._raise_error("create", resp) return decode_result(request_indication.path, resp.payload, resp.content_format) def _send_delete(self, request_indication, path): resp = self.client.delete(path) if resp.code >= 100: self._raise_error("create", resp) return DeleteResponseConfirmation() def create(self, path, resource): return self.send_request_indication( CreateRequestIndication(path, resource)) def update(self, resource, fields=()): return self.send_request_indication( UpdateRequestIndication(resource.path, resource, fields=fields)) def retrieve(self, path): return self.send_request_indication(RetrieveRequestIndication(path)) def delete(self, path): return self.send_request_indication(DeleteRequestIndication(path))
class XIXCoap(LoggerMixin): """XIXCoap serializes RequestIndications to CoAP messages and sends them using a CoapClient""" def __init__(self, uri, client_port=None, scl_base=None, use_xml=False, keyfile=None, certfile=None, block_size_exponent=10, *args, **kw): """Initializes XIXCoap and its underlying CoapClient :param uri:URI referencing the server this clients is trying to reach. Can contain SCHEME://IP:PORT :param client_port: Port used by the client when sending requests :param scl_base: Default basename to prefix an SCL resource path :param use_xml: Binary parameter swapping between content types of xml and json """ self.client = CoapClient(uri, client_port or 25682, keyfile=keyfile, certfile=certfile, block_size_exponent=block_size_exponent) self.scl_base = scl_base self.logger.debug("CoapClient created with uri %s", uri) if use_xml: from openmtc_etsi.serializer.xml import XMLSerializer as Serializer self.content_type = "application/xml" else: from openmtc_etsi.serializer.json import JsonSerializer as Serializer self.content_type = "application/json" self.__serializer = Serializer() self.methodmappers = { "create": self._send_create, "notify": self._send_notify, "update": self._send_update, "delete": self._send_delete, "retrieve": self._send_retrieve } def send_request_indication(self, request_indication): """Serializes a RequestIndication to a CoAP message and sends it using a CoapClient :param request_indication: RequestIndication to be processed :return: Corresponding ResponseConfirmation """ if self.scl_base is not None and \ not request_indication.path.startswith(self.scl_base) and \ "://" not in request_indication.path: request_indication.path = self.scl_base + request_indication.path path = request_indication.path if path.startswith('/'): path = path[1:] mapper = self.methodmappers[request_indication.method] return mapper(request_indication, path) def _raise_error(self, method, response): """Handles reponses containing an error status code. Generates an ErrorResponseConfirmation. :param method: Request method, can be "create", "notify", "update", "delete" or "retrieve" :param response: CoAP response """ try: status_code = _coap2etsi[response.code] except KeyError: self.logger.warning("Failed to map coap response code: %s", response.code) status_code = openmtc_etsi.exc.STATUS_INTERNAL_SERVER_ERROR except AttributeError: self.logger.warning("No response for %s", method) status_code = openmtc_etsi.exc.STATUS_INTERNAL_SERVER_ERROR if response and hasattr(response, "payload"): raise ErrorResponseConfirmation( statusCode=status_code, primitiveType=method, errorInfo=response.payload or "<no further information available>") else: raise ErrorResponseConfirmation( statusCode=status_code, primitiveType=method, errorInfo=response or "<no further information available>") def _send_create(self, request_indication, path): """Serializes a CreateRequestIndication to a CoAP POST message and sends it using a CoapClient :param request_indication: CreateRequestIndication to be processed :param path: Resource path :return: Corresponding CreateResponseConfirmation """ if request_indication.content_type: data = request_indication.resource else: data = self.__serializer.encode_values(request_indication.typename, request_indication.resource) def handle_response(resp): if resp.code >= 100: self._raise_error("create", resp) location = resp.findOption(8) if location: return CreateResponseConfirmation(location[0].value, resp.payload) else: return CreateResponseConfirmation(resp.payload) return self.client.post( path, data, content_type=self.content_type).then(handle_response) def _send_notify(self, request_indication, path): """Serializes a NotifyRequestIndication to a CoAP POST message and sends it using a CoapClient :param request_indication: NotifyRequestIndication to be processed :param path: Resource path :return: Corresponding NotifyResponseConfirmation """ if request_indication.content_type: data = request_indication.resource else: data = self.__serializer.encode_values(request_indication.typename, request_indication.resource) def handle_response(resp): if resp.code >= 100: self._raise_error("notify", resp) return NotifyResponseConfirmation() return self.client.post( path, data, content_type=self.content_type).then(handle_response) def _send_update(self, request_indication, path): """Serializes a UpdateRequestIndication to a CoAP POST message and sends it using a CoapClient :param request_indication: UpdateRequestIndication to be processed :param path: Resource path :return: Corresponding UpdateResponseConfirmation """ if request_indication.content_type: data = request_indication.resource else: data = self.__serializer.encode_values(request_indication.typename, request_indication.resource) def handle_response(resp): if resp.code >= 100: self._raise_error("update", resp) return UpdateResponseConfirmation() return self.client.put( path, data, content_type=self.content_type).then(handle_response) def _send_retrieve(self, request_indication, path): """Serializes a RetrieveRequestIndication to a CoAP GET message and sends it using a CoapClient :param request_indication: RetrieveRequestIndication to be processed :param path: Resource path :return: Corresponding RetrieveResponseConfirmation """ # TODO: Accept must be set dynamically self.logger.debug("send retrieve path %s" % path) def handle_response(resp): if resp.code >= 100: self._raise_error("retrieve", resp) if resp.code == VALID: return RetrieveResponseConfirmation(None) else: d, ct = decode_result(request_indication.path, resp.payload, resp.content_format) return RetrieveResponseConfirmation(resource=d, content_type=ct) return self.client.get(path, accept=50).then(handle_response) def _send_delete(self, request_indication, path): """Serializes a DeleteRequestIndication to a CoAP DELETE message and sends it using a CoapClient :param request_indication: DeleteRequestIndication to be processed :param path: Resource path :return: Corresponding DeleteResponseConfirmation """ def handle_response(resp): if not resp or resp.code >= 100: self._raise_error("delete", resp) else: return DeleteResponseConfirmation() return self.client.delete(path).then(handle_response) def create(self, path, resource): """Creates and serializes a CreateRequestIndication to a CoAP POST message and sends it using a CoapClient :param path: Resource path :param resource: Request payload :return: Corresponding CreateResponseConfirmation """ return self.send_request_indication( CreateRequestIndication(path, resource)) def update(self, resource, fields=()): """Creates and serializes a UpdateRequestIndication to a CoAP PUT message and sends it using a CoapClient :param path: Resource path :return: Corresponding UpdateResponseConfirmation """ return self.send_request_indication( UpdateRequestIndication(resource.path, resource, fields=fields)) def retrieve(self, path): """Creates and serializes a RetrieveRequestIndication to a CoAP GET message and sends it using a CoapClient :param path: Resource path :return: Corresponding RetrieveResponseConfirmation """ return self.send_request_indication(RetrieveRequestIndication(path)) def delete(self, path): """Creates and serializes a DeleteRequestIndication to a CoAP DELETE message and sends it using a CoapClient :param path: Resource path :return: Corresponding DeleteResponseConfirmation """ return self.send_request_indication(DeleteRequestIndication(path))
#Coap Client example #PYTHONPATH=../:../../src:../../../futile/src python SimpleTestClient.py from coap import CoapClient import ast import json """ Create a client instance with the server IP and port Note that coap:// is mandatory here """ #client = CoapClient("coap://ns.tzi.org:61616") client = CoapClient("coap://localhost:5684") """ Some example of requests, the return is always a promise object 1st param: ressource path 2nd param: payload Optional params: 'content_type', 'max_age', 'uri_scheme', 'etag', 'uri_authority', 'location' """ #p=client.post("sink","data") #p=client.put("rd?ep=test","data") #p=client.delete("ressource_name") p = client.post("rd?ep=node1<=4500&version=1&binding=U", "3/1/1, 4/1/2") #p=client.post("rd?ep=node2<=9000&version=5&binding=UP","3/2/2") p = client.get("rd?ep=node1") #<=4500&version=1&binding=U" #, content_type='JSON' #This fails: #p=client.get("mes") #This works: #p=client.get("res") """
certpath = '/opt/OpenMTC/openmtc-python/openmtc-gevent/certs/' #for dtls and ca certificate usage keyfile = certpath + 'CA_and_certs/pydtls/client/client-keycert.pem' certfile = certpath + 'CA_and_certs/pydtls/client/client-cert.pem' cacertfile = certpath + 'CA_and_certs/pydtls/ca/ca-cert.pem' #keyfile = '/opt/OpenMTC/openmtc-python/openmtc/lib/ocsp/test/certs/validprivkey.pem' #certfile = '/opt/OpenMTC/openmtc-python/openmtc/lib/ocsp/test/certs/validcert.pem' """ Create a client instance with the server IP and port Note that coap:// is mandatory here """ #client = CoapClient("coap://vs0.inf.ethz.ch:5685/") client = CoapClient("coap://localhost:4000", client_port=9876) # client = CoapClient("coaps://localhost:6000", keyfile=keyfile, certfile=certfile, cacertfile=cacertfile) # client = CoapClient("coap://130.149.247.213:8090", client_port=9876) # client = CoapClient("coap://130.149.247.214:8090", client_port=9876) # client = CoapClient("coap://130.149.247.215:8090", client_port=9876) #client = CoapClient("coap://coap.me:5683") def resultPrinter(result): print "got result:" print result def errorPrinter(error): print "got error:" print error
def run(start_port=10000, reqPerS=100, filename="data"): """Config Constants""" # Number of requests to be sent NUM_REQ = 500 # int(10/(1.0/reqPerS)) # Used method (POST or GET) METHOD = "GET" # Path to retrieve in case of GET GET_PATH = 'm2m' # Size of the randomly generated payload for post requests (in bytes) POST_PAYLOAD_SIZE = 200 # If CONCURRENCY is set to True, a new thread sending a request is created every CONCURRENCY_INTERVAL seconds # If CONCURRENCY is set to False, requests wait for a reply before sending a new one (optimal) CONCURRENCY = False CONCURRENCY_INTERVAL = 1.0 / reqPerS """Initialization""" if METHOD == "POST": print "Started, sending %s %s requests on %s\n" % (NUM_REQ, METHOD, IP) print "Post Payload is %s" % POST_PAYLOAD_SIZE else: print "Started, sending %s %s requests on %s/%s\n" % (NUM_REQ, METHOD, IP, GET_PATH) if CONCURRENCY: print "Concurrency interval %s\n" % CONCURRENCY_INTERVAL else: print "Concurrency is Off\n" client = CoapClient(IP) if METHOD == "POST": val = "".join( [str(randrange(10)) for n in range(POST_PAYLOAD_SIZE - 12)]) def repeat_post(client): client.post( 'm2m/applications/apptest/containers/cont1/contentInstances', '{"value":"' + val + '"}', content_type='application/json', block1={"size_exponent": 6}) def repeat_get(client): client.get(GET_PATH) """Concurrent Measurement loops""" def measure_post(i): if (i + 1) % 50 == 0: print "%s requests processed" % (i + 1) client = CoapClient(IP, client_port=i + start_port) t = timeit(lambda: repeat_post(client), number=1) t_list.append(t) avg = 0 for tt in t_list: avg += tt avg = avg / len(t_list) f = open(filename, 'a') f.write('%s %s\n' % (str(t), avg)) f.close() def measure_get(i): if (i + 1) % 50 == 0: print "%s requests processed" % (i + 1) client = CoapClient(IP, client_port=i + 10000) t = timeit(lambda: repeat_get(client), number=1) t_list.append(t) avg = 0 for tt in t_list: avg += tt avg = avg / len(t_list) f = open(filename, 'a') f.write('%s %s\n' % (str(t), avg)) f.close() """Method differentiation""" if METHOD == "POST": if CONCURRENCY: t_list = [] for i in range(NUM_REQ): t = threading.Thread(target=lambda: measure_post(i)) t.start() sleep(CONCURRENCY_INTERVAL) sleep(10) else: t_list = repeat(lambda: repeat_post(client), number=1, repeat=NUM_REQ) strin = "\n".join(map(str, t_list)) f = open(filename, 'a') f.write('%s' % strin) f.close() elif METHOD == "GET": if CONCURRENCY: t_list = [] for i in range(NUM_REQ): thr = threading.Thread(target=lambda: measure_get(i)) thr.start() sleep(CONCURRENCY_INTERVAL) sleep(2) else: t_list = repeat(lambda: repeat_get(client), number=1, repeat=NUM_REQ) strin = "\n".join(map(str, t_list)) f = open(filename, 'a') f.write('%s' % strin) f.close() """Overall output""" t = 0 for time in t_list: t = time + t total_req = len(t_list) print "Total experiment time: %ss" % t print "Number of req sent: %s" % NUM_REQ print "Number of req recv: %s" % total_req print "Req rate: %f req/s , %.3f req/ms" % (total_req / t, total_req / (t * 1000)) print "Average RTT: %fms" % ((t / float(total_req)) * 1000.0)