class Node(threading.Thread): def __init__(self,port=-1,ip_list=None,port_list=None,end_type=0,total_num=0,entry_num=0,exit_num=0): """ end_type 0 is exit, 1 is entry """ threading.Thread.__init__(self) self.port = port self.ip_list = ip_list self.port_list = port_list self.ip = socket.gethostbyname(socket.gethostname()) #print self.ip self.end_type = end_type self.state = StateInfo(total_num,entry_num,exit_num) self.counter = 0 self.reject_critical = False self.update_flag = False # Wait fot the update reply from all other nodes self.isCoorn = False # Not Coordinator self.inCritical = 0 #Not in critical region self.message_queue = [] self.update_repley_procset = set() self.max_num = total_num if self.port == max(self.port_list): self.set_coordinator() self.start() def set_coordinator(self): self.isCoorn = True self.cri_proc = None #who is in the critical region self.wait_queue = list() def sort_insert2waitqueue(self,message): if not self.wait_queue: self.wait_queue.append(message) elif self.wait_queue[0].data[1] > message.data[1]: self.wait_queue.insert(0,message) elif self.wait_queue[len(self.wait_queue)-1].data[1] < message.data[1]: self.wait_queue.append(message) else: for index in range(len(self.wait_queue)-1): if self.wait_queue[index].data[1] < message.data[1] and self.wait_queue[index+1].data[1] > message.data[1]: self.wait_queue.insert(index,message) def sort_insert2messqueue(self,message): if not self.message_queue: self.message_queue.append(message) elif self.message_queue[0].data[1] > message.data[1]: self.message_queue.insert(0,message) elif self.message_queue[len(self.message_queue)-1].data[1] < message.data[1]: self.message_queue.append(message) else: for index in range(len(self.message_queue)-1): if self.message_queue[index].data[1] < message.data[1] and self.message_queue[index+1].data[1] > message.data[1]: self.message_queue.insert(index,message) def send_message(self,ip,port,message): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip,port)) data = pickle.dumps(message) s.send(data) s.close() def update_lamport_clock(self,message): data = message.data timestamp = data[1] #update clock self.counter = max(timestamp,self.counter) #increase VC def process_mess(self): while True: #sprint("process_mess "+str(len(self.message_queue))) if self.message_queue: message = self.message_queue[0] while True: if message.mess_type == PARK_UPDATE_TYPE: break if not self.reject_critical: break self.message_queue.remove(message) if message.mess_type == ACK_CRI_TYPE: # a node trys to enter the critical if self.isCoorn: #Coordinator data = message.data pro_id = data[0] src_ip = data[2] src_port = data[3] self.update_textplane("<->node "+str(src_port)+" want to enter c_r\n") if self.cri_proc and not self.cri_proc == src_port: # wait #sorted wait queue data = [] data.append(os.getpid()) data.append(self.counter) data.append(self.ip) data.append(self.port) reject_message = MessageData(REJECT_REPLY_TYPE,self.state,data) self.send_message(src_ip,src_port,reject_message) self.sort_insert2waitqueue(message) else: # enter the critical region okay self.update_textplane("<->node "+str(src_port)+" enter c_r\n") print("Enter the critical region\n") self.cri_proc = src_port data = [] data.append(os.getpid()) data.append(self.counter) data.append(self.ip) data.append(self.port) ok_message = MessageData(ACK_REPLY_TYPE,self.state,data) self.send_message(src_ip,src_port,ok_message) elif message.mess_type == PARK_UPDATE_TYPE: stateInfo = message.state_info self.state = StateInfo(stateInfo.total_num,stateInfo.entry_num,stateInfo.exit_num) data_part = message.data pro_id = data_part[0] src_ip = data_part[2] src_port = data_part[3] self.update_textplane("<->update stateinfo from node "+str(src_port)+"\n") data = [] data.append(os.getpid()) data.append(self.counter) data.append(self.ip) data.append(self.port) update_reply_message = MessageData(UPDATE_REPLY_TYPE,self.state,data) #self.message2send.append(ok_message) self.send_message(src_ip,src_port,update_reply_message) elif message.mess_type == ACK_REPLY_TYPE:# ACK of the #self.ack_critical = True #OK ,can enter the critical region #print("RECV the ack reply type\n") self.update_textplane("<->node "+str(self.port)+" enter the c_r\n") self.update_flag = False ##TBD self.change_state() #send the update type to other nodes time.sleep(5) data = message.data pro_id = data[0] src_ip = data[2] src_port = data[3] for index in range(len(self.port_list)): #print "port: "+str(self.port_list[index]) if not self.port_list[index] == self.port: data = [] data.append(os.getpid()) data.append(self.counter) data.append(self.ip) data.append(self.port) park_update_message = MessageData(PARK_UPDATE_TYPE,self.state,data) self.send_message(self.ip_list[index],self.port_list[index],park_update_message) while True: if self.update_flag: break self.update_textplane("<->node "+str(self.port)+" leave the c_r\n") self.update_flag = False self.reject_critical = False data = [] data.append(os.getpid()) data.append(self.counter) data.append(self.ip) data.append(self.port) leave_message = MessageData(LEAVE_TYPE,self.state,data) self.send_message(src_ip,src_port,leave_message) elif message.mess_type == LEAVE_TYPE: #release the critical region if self.isCoorn: data = message.data src_port = data[3] self.update_textplane("<->node "+str(src_port)+" leave the c_r\n") self.cri_proc = None if self.wait_queue: message = self.wait_queue[0] self.wait_queue.remove(message) wait_data = message.data src_ip = wait_data[2] src_port = wait_data[3] data = [] data.append(os.getpid()) data.append(self.counter) data.append(self.ip) data.append(self.port) ok_message = MessageData(ACK_REPLY_TYPE,self.state,data) self.send_message(src_ip,src_port,ok_message) elif message.mess_type == REJECT_REPLY_TYPE: self.update_textplane("<->wait to enter the c_r\n") self.reject_critical = True #else: # mess_type == UPDATE_REPLY_TYPE: #nothing to be processed #data = message.data #self.update_repley_procset.add(data[0]) #if len(self.update_repley_procset)==(len(self.port_list)-1): #exclude the process itself # self.update_flag = True def conn_proc(self,s): while(True): sock, addr = s.accept() data = sock.recv(4068) message = pickle.loads(data) #print("recv message "+str(message.mess_type)) self.update_lamport_clock(message) if message.mess_type == UPDATE_REPLY_TYPE: data = message.data self.update_repley_procset.add(data[3]) if len(self.update_repley_procset)>=(len(self.port_list)-1): #exclude the process itself print "" self.update_flag = True self.update_repley_procset = set() else: if message.mess_type == ACK_REPLY_TYPE: print str(self.port)+"recv ACK_REPLY_TYPE" self.reject_critical = False self.sort_insert2messqueue(message) sock.close() def ack_for_cri(self): data = [] data.append(os.getpid()) data.append(self.counter) data.append(self.ip) data.append(self.port) state = self.state ack_cri_message = MessageData(ACK_CRI_TYPE,state,data) critical_port = max(self.port_list) ip_index = self.port_list.index(critical_port) print "ip "+str(self.ip)+" port"+str(self.port) print "to connect ip: "+str(self.ip_list[ip_index])+" port: "+str(critical_port) self.send_message(self.ip_list[ip_index],critical_port,ack_cri_message) def change_state(self): print("change_state********************************************\n") if self.end_type == 1: if self.state.total_num>0: self.state.decre_total_num(1) self.text_plane.insert(1.0,"A car enter!\n") else: if self.state.total_num < self.max_num: self.state.incre_total_num(1) self.text_plane.insert(1.0,"A car leave!\n") def update_textplane(self,text): self.text_plane.insert(1.0,text) def quit(self): self.frame.destroy() self.frame.quit() def get_state(self): text = "REST_NUM: "+str(self.state.total_num)+", ENTRY_NUM: "+str(self.state.entry_num)+", EXIT_NUM: "+str(self.state.exit_num)+"\n" self.update_textplane(text) def run(self): self.frame = Tk() text = str(self.port) button_text = '' if self.end_type == 0: text += ": exit" button_text = 'Leave now' else: text += ": entry" button_text = 'Enter now' self.frame.title(text) #self.frame.geometry('300x200') self.text_plane = Text(self.frame,height=6,width=45) self.text_plane.pack() Button(self.frame, text=button_text,command=self.ack_for_cri).pack() Button(self.frame, text="State Info",command=self.get_state).pack() s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.bind(('',self.port)) s.listen(5) print('ip port'+str(self.ip)+' '+str(self.port)) #thread to recv the message t1 = threading.Thread(target=self.conn_proc,args=(s,)) t1.start() #thread to process the message t2 = threading.Thread(target=self.process_mess) t2.start() #while True: # time.sleep(1) # print(1) self.frame.mainloop()