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()