Python uses socket for multi-threaded sending and receiving and path calculation to simulate router network

Python uses socket for multi-threaded sending and receiving and path calculation to simulate router network


For coursework, use multithreading to simultaneously broadcast information and receive information through a socket on a port, and Dijkstra path calculation to simulate the simple behavior of a router in a network.
The profile comprising:
a router port name as the run
number of initial router near the known
initial router name known to the vicinity of the distance run and the port address
e.g. configAE.txt file:

AE 7001
2
BW 3.1 7003
DR 2.7 7007

Run the startup script under windows:

start cmd /k "python router.py configAE.txt"

Code file router.py

#!/usr/bin/python3.7

import socket
import sys
import threading
import time
import operator
import copy

# 获取精度到秒的时间戳
def get_time():
	return int(time.time())
	
# 创建发送的信息
def create_msg():
	msg = router_id + ' ' + str(router_port) + ' ' + str(get_time()) + '\n'
	msg = msg + "neighbour\n"
	for ID in neighbour_list.keys():
		msg = msg + ID + ' ' + str(neighbour_list[ID].get_port()) + ' '\
			+ str(neighbour_list[ID].get_cost()) + '\n'
	return msg
	
# 读取接收的信息
def deal_msg(msg):
	if msg == "":
		return -1
	lines = msg.split("\n")
	creater = lines[0].split(" ")
	creater_id = creater[0]
	creater_port = creater[1]
	creater_time = int(creater[2])
	
	# if it is created by itself
	if creater_id == router_id:
		return -1
	
	# if it is a path information
	if lines[1] == "neighbour":
		# if it is a recur router
		if creater_id in dead_list:
			router_recieve_list[creater_id] = creater_time
			dead_list.remove(creater_id)
			temp_dic = {
    
    }
			for line in lines[2:-1]:
				info = line.split(" ")
				temp_dic[info[0]] = [int(info[1]),float(info[2])]
			if operator.eq(temp_dic, all_route[creater_id]) != 0:
				all_route[creater_id] = temp_dic
			return creater_id
			
		# if it is a new router
		if creater_id not in router_recieve_list.keys()\
			or creater_id not in all_route.keys():
			router_recieve_list[creater_id] = creater_time
			temp_dic = {
    
    }
			for line in lines[2:-1]:
				info = line.split(" ")
				temp_dic[info[0]] = [int(info[1]),float(info[2])]
			all_route[creater_id] = temp_dic
			return 0
			
		# if just normal update
		else:
			# if it is an old message which do not need to deal with
			if creater_time <= router_recieve_list[creater_id]:
				return -1
			# if it is a useful message
			else:
				router_recieve_list[creater_id] = creater_time
				temp_dic = {
    
    }
				for line in lines[2:-1]:
					info = line.split(" ")
					temp_dic[info[0]] = [int(info[1]),float(info[2])]
				if operator.eq(temp_dic, all_route[creater_id]) == 0:
					return 0 # do nothing
				# replace it
				else:
					all_route[creater_id] = temp_dic
					return 0		
	elif lines[1] == "dead":
		if creater_id not in router_recieve_list.keys():
			router_recieve_list[creater_id] = creater_time
		elif creater_time <= router_recieve_list[creater_id]:
			return -1
		if lines[2] not in dead_list and lines[2] != router_id:
			dead_list.append(lines[2])
			return 0
	elif lines[1] == "resur":
		if creater_id not in router_recieve_list.keys():
			router_recieve_list[creater_id] = creater_time
		elif creater_time <= router_recieve_list[creater_id]:
			return -1
		if lines[2] in dead_list:	
			dead_list.remove(lines[2])
			return 0

# Dijkstra算法与打印输出
def Dijkstra():
	# delete all the dead route
	temp_routers = copy.deepcopy(all_route)
	for ID in dead_list:
		if ID != router_id:
			if ID in temp_routers.keys():
				del temp_routers[ID]
			for router in temp_routers.keys():
				if ID in temp_routers[router].keys():
					del temp_routers[router][ID]
	
	# start caculate
	unvisit_nodes = [ID for ID in temp_routers.keys()]
	visited_nodes = []
	# initialize
	for ID in unvisit_nodes:
		# {ID: previous node, cost}
		cost_list[ID] = ['', float('inf')]
	# first point
	cost_list[router_id] = ['', 0.0]
	# all neighbours
	for ID in all_route[router_id].keys():
		cost_list[ID] = [router_id, all_route[router_id][ID][1]]
	unvisit_nodes.remove(router_id)
	visited_nodes.append(router_id)
	# start loop
	while len(unvisit_nodes) != 0:
		# find the shortest unvisit node
		min_cost = float('inf')
		min_id = ''
		for ID in unvisit_nodes:
			if cost_list[ID][1] <= min_cost:
				min_cost = cost_list[ID][1]
				min_id = ID
		# start from min_id, for all neighbours
		for ID in all_route[min_id].keys():
			if ID in unvisit_nodes:
				cost = round(min_cost + all_route[min_id][ID][1], 6)
				# if it is a shorter path
				if cost < cost_list[ID][1]:
					cost_list[ID] = [min_id, cost]
		# mark the node
		unvisit_nodes.remove(min_id)
		visited_nodes.append(min_id)
					
	# print result
	print("I am Router " + router_id)
	visited_nodes.remove(router_id)
	visited_nodes.sort()
	for ID in visited_nodes:
		path = ID
		temp = ID
		while cost_list[temp][0] != '':
			path = cost_list[temp][0] + path
			temp = cost_list[temp][0]
		print("Least cost path to router " + ID + ": " \
			+ path + " and the cost is " + str(cost_list[ID][1]))
	print()

# 为记录中的路由器创建一个类来记录
class router:
	def __init__(self, ID, cost, port):
		self.ID = ID
		self.cost = cost
		self.port = port
		
	def get_id(self):
		return self.ID
	
	def get_cost(self):
		return self.cost
	
	def get_port(self):
		return self.port
	
# 广播线程
class broadcast(threading.Thread):
	def __init__(self, threadID, name, interval, soc):
		threading.Thread.__init__(self)
		self.threadID = threadID
		self.name = name
		self.interval = interval
		self.soc = soc
	def run(self):
		while True:
			msg = create_msg()
			msg = msg.encode(encoding='UTF-8')
			for ID in neighbour_list.keys():
				self.soc.sendto(msg, ("127.0.0.1", neighbour_list[ID].get_port()))
			time.sleep(self.interval)

# 接收线程		
class recieve(threading.Thread):
	def __init__(self, threadID, name, soc):
		threading.Thread.__init__(self)
		self.threadID = threadID
		self.name = name
		self.soc = soc
	def run(self):
		while True:
			msg = ""
			addr = ""
			try:
				data, addr = self.soc.recvfrom(2048)
				msg = data.decode(encoding='UTF-8')
			except:
				pass
			#print(msg,"from",addr)
			result = deal_msg(msg)
			if result == 0: # if it is not an old message, broadcast it
				for ID in neighbour_list.keys():
					self.soc.sendto(data, ("127.0.0.1", neighbour_list[ID].get_port()))
			# some router is recur
			elif type(result) == str:
				recur_msg = router_id + ' ' + str(router_port) + ' ' + str(get_time()) + '\n'
				recur_msg = recur_msg + "resur\n" + result + "\n"
				recur_msg = recur_msg.encode(encoding='UTF-8')
				for ID in neighbour_list.keys():
					self.soc.sendto(recur_msg, ("127.0.0.1", neighbour_list[ID].get_port()))			
			# for test
			#print(msg,"deal with from",addr)

# 计算线程				
class calculate(threading.Thread):
	def __init__(self, threadID, name, soc):
		threading.Thread.__init__(self)
		self.threadID = threadID
		self.name = name
		self.soc = soc
	def run(self):
		while True:
			time.sleep(ROUTE_UPDATE_INTERVAL)
			now = get_time()
			for ID in neighbour_list.keys():
				# if a router is dead
				if ID in router_recieve_list.keys():
					if now - router_recieve_list[ID] > 10 and ID not in dead_list:
						dead_list.append(ID)
						dead_msg = router_id + ' ' + str(router_port) + ' ' + str(get_time()) + '\n'
						dead_msg = dead_msg + "dead\n" + ID + "\n"
						dead_msg = dead_msg.encode(encoding='UTF-8')
						for ID in neighbour_list.keys():
							self.soc.sendto(dead_msg, ("127.0.0.1", neighbour_list[ID].get_port()))	
			
			Dijkstra()

# 读取文件信息
filepath = sys.argv[1]

# set parameter
UPDATE_INTERVAL = 1
ROUTE_UPDATE_INTERVAL = 30

router_id = 0
router_port = 0
# total number of neighbours
neighbour_number = 0
# {ID: class router}, only for neighbours
neighbour_list = {
    
    }
# {ID: timestamp}, last time recieve broadcast created by the router
router_recieve_list = {
    
    }
# all routers in the whole net
# like {A: {B:[5001,2],C:[5003,5]}}, means A to B is 2, only A's neighbours
all_route = {
    
    }
# dead router
dead_list = []
# # {ID: previous node, cost}, store the result of Dijkstra’s algorithm
cost_list = {
    
    }

with open(filepath) as input_file:
	input_lines = input_file.readlines()
	router_id = input_lines[0].split(" ")[0]
	router_port = int(input_lines[0].split(" ")[1])
	neighbour_number = int(input_lines[1])
	all_route[router_id] = {
    
    }
	for i in range(0, neighbour_number):
		line = input_lines[i+2]
		line = line.split(" ")
		neighbour_id = line[0]
		neighbour_cost = float(line[1])
		neighbour_port = int(line[2])
		neighbour_list[neighbour_id] = router(neighbour_id, neighbour_cost, neighbour_port)
		all_route[router_id][neighbour_id] = [neighbour_port, neighbour_cost]
# 文件信息读取完毕

# 创建线程
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
soc.bind(("127.0.0.1", router_port))
thread_broadcast = broadcast(1, "broadcast", UPDATE_INTERVAL, soc)
thread_recieve = recieve(2, "recieve", soc)
thread_calculate = calculate(3, "calculate", soc)

# 启动线程
thread_broadcast.start()
thread_recieve.start()
thread_calculate.start()

Guess you like

Origin blog.csdn.net/starvapour/article/details/108415656