class Node: __executor__ = ThreadPoolExecutor(max_workers=10) __clock__ = Clock() __msg_queue__ = None __terminate__ = False def __init__(self, node_id, dst=None, msg=None, timestamp=None): self.nid = node_id self.dst = dst self.msg = msg self.timestamp = timestamp self.fromfilename = 'from' + self.nid + '.txt' self.tofilename = 'to' + self.nid + '.txt' self.receivefilename = self.nid + 'received.txt' self.__message_processor__ = { 'HELLO': self.__receive_hello__, 'TC': self.__receive_tc__, 'DATA': self.__receive_data__ } self.__msg_cache__ = dict() self.__route__ = Route(node_id) def __msg_cache_reset__(self): """ Reset cache for new message forwading period. """ self.__msg_cache__ = dict() @property def time(self): return self.__clock__.time def tick(self): self.__clock__.tick() __hello__ = '* {} HELLO UNIDIR {} BIDIR {} MPR {}\n' def __send_hello__(self): sender = self.nid unidir = ' '.join(map(str, self.__route__.unidir)) bidir = ' '.join(map(str, self.__route__.bidir)) mpr = ' '.join(map(str, self.__route__.mpr)) hello = self.__hello__.format(sender, unidir, bidir, mpr) # print(hello) with open(self.fromfilename, 'a') as from_me: from_me.write(hello) __tc__ = '* {} TC {} {} MS {}\n' def __send_tc__(self): sender = self.nid source = self.nid seqno = self.__route__.ms_seqno ms = ' '.join(map(str, self.__route__.ms)) tc = self.__tc__.format(sender, source, seqno, ms) with open(self.fromfilename, 'a') as from_me: from_me.write(tc) __data__ = '{} {} DATA {} {} {}\n' def __send_data__(self): next_hop = self.__route__.get_route(self.dst) # If next_hop is not None, send message to that node. if next_hop: sender = self.nid originator = self.nid dst = self.dst msg = self.msg data = self.__data__.format(next_hop, sender, originator, dst, msg) with open(self.fromfilename, 'a') as from_me: from_me.write(data) # Otherwise, delay the message for 30 seconds. else: self.timestamp += 30 def __check_timeout__(self): self.__route__.check_timeout() def __follow_to_file__(self): try: open(self.tofilename, 'r').close() except IOError: open(self.tofilename, 'w').close() with open(self.tofilename, 'r') as to_me: to_me.seek(0, 2) while not self.__terminate__: line = to_me.readline() if not line: sleep(0.1) continue yield line def __receive_hello__(self, msg): with open(self.receivefilename, 'a') as received: received.write(msg) msg = msg[:-1] neighbor = msg[2] unidir, rest = msg.split('UNIDIR ')[1].split(' BIDIR ') bidir, mpr = rest.split(' MPR ') to_set = lambda x: set() if x == '' else set(x.split(' ')) self.__route__.hello_update(neighbor, to_set(unidir), to_set(bidir), to_set(mpr)) def __receive_tc__(self, msg): with open(self.receivefilename, 'a') as received: received.write(msg) msg = msg[:-1] neighbor = msg[2] s, ms = msg.split(' TC ')[1].split(' MS ') source, seqno = s.split(' ') # If the TC message was originated by the node itself, discard it. if source == self.nid: return # If the TC message in cache is newer or the same (cache[source] >= # seqno), discard it. try: if self.__msg_cache__[source] >= seqno: return except KeyError: pass finally: self.__msg_cache__[source] = seqno to_set = lambda x: set() if x == '' else set(x.split(' ')) self.__route__.tc_update(source, to_set(ms), int(seqno)) # Forward message if node itself is sender's mpr and TTL is greater # than 1. if self.__route__.mpr_of(neighbor): tc = self.__tc__.format(self.nid, source, seqno, ms) with open(self.fromfilename, 'a') as from_me: from_me.write(tc) def __receive_data__(self, msg): with open(self.receivefilename, 'a') as received: received.write(msg) msg_list = msg[:-1].split(' ') # If current node is the destination of the message, no further # operation is needed. if self.nid == msg_list[4]: return # Otherwise, get next hop to the destination, forward the message. next_hop = self.__route__.get_route(msg_list[4]) # If next_hop is not None, forward the message to that node. Change # next_hop and fromnbr before sending. if next_hop: new_msg = ' '.join([next_hop, self.nid] + msg_list[2:]) + '\n' with open(self.fromfilename, 'a') as from_me: from_me.write(new_msg) # Otherwise, just drop the message. else: pass def __msg_processor__(self): for msg in self.__msg_queue__: self.__message_processor__[msg.split(' ')[2]](msg) if self.__terminate__: break def start(self): self.__msg_queue__ = \ (self.__executor__.submit(self.__follow_to_file__)).result() self.__executor__.submit(self.__msg_processor__) while self.time <= 122: self.__executor__.submit(self.__check_timeout__) # Send message at specific timestamp. if self.time == self.timestamp: self.__executor__.submit(self.__send_data__) # Each node sends a hello message every 5 seconds. if self.time % 5 == 0: self.__executor__.submit(self.__send_hello__) # Reset message cache before each TC flood time cycle. if self.time % 10 == 8: self.__executor__.submit(self.__msg_cache_reset__) # Every node with a non-empty MS sets creates and floods a TC # message every 10 seconds. if self.time % 10 == 0 and self.__route__.ms: self.__executor__.submit(self.__send_tc__) sleep(1) self.tick() self.__terminate__ = True sleep(1)