python使用socket进行多线程收发与路径计算模拟路由器网络

python使用socket进行多线程收发与路径计算模拟路由器网络


课设作业,使用多线程方式通过一个端口上的socket同时进行广播信息,接收信息,Dijkstra路径计算来模拟一个网络中路由器的简单行为。
配置文件中包含:
路由器名称与运行端口
初始所知的附近路由器数量
初始所知的附近路由器名称,距离与运行端口地址
例如configAE.txt文件:

AE 7001
2
BW 3.1 7003
DR 2.7 7007

windows下运行启动脚本:

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

代码文件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()

你可能感兴趣的:(学习笔记,网络,python,多线程)