新版本代码

main
陈玉辉 5 months ago
parent c6c69dc88e
commit dce7050b15

@ -0,0 +1,944 @@
import ipaddress
import sys
import threading
from tkinter import filedialog
from SimUtil import *
from SimObjs import SimPacket, SimHost, AllSimConnect, SimRouter, SimSwitch, SimHub, SimBase
from dbUtil import search, execute_sql, delete_obj, truncate_db
from PIL import Image as imim
class Message(Canvas):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.message = []
self.master = master
self.scrollbar = tk.Scrollbar(master, orient="vertical", command=self.yview)
self.scrollbar.pack(side="right", fill=BOTH)
self.config(yscrollcommand=self.scrollbar.set)
def show_message(self, message, color="#5fa8fe"):
self.message.append({"message": message, "color": color})
num = 0
self.delete("message")
for function in self.message:
self.create_text(20, 25 * num + 10, anchor="nw", text=function["message"], font=("", 15),
fill=function["color"], tags="message")
num += 1
self.update()
self.configure(scrollregion=self.bbox("all"))
self.scrollbar.set(1.0, 1.0)
self.yview_moveto(1.0)
class NetWorkAnalog(Canvas):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.master = master
self.router_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/路由器@2x.png").resize((40, 40)))
self.switch_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/交换机@2x.png").resize((40, 40)))
self.hub_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/集线器@2x.png").resize((40, 40)))
self.host_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机@2x.png").resize((40, 40)))
self.pack_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/packet.png").resize((30, 30)))
self.true_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/true.png").resize((30, 30)))
self.false_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/false.png").resize((30, 30)))
self.width = int(self.cget("width"))
self.height = int(self.cget("height"))
self.canvas_size = [150, 0, int(self.width * 0.8), int(self.height * 0.8)]
self.label_top_img = ImageTk.PhotoImage(imim.open("../datas/images/右上框@2x.png").resize((int(self.width - self.width * 0.85), int(self.canvas_size[3] * 0.4))))
self.label_bottom_img = ImageTk.PhotoImage(imim.open("../datas/images/右下框@2x.png").resize((int(self.width - self.width * 0.85), int(self.canvas_size[3] * 0.45))))
self.message_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/日志消息展示框@2x.png").resize((self.width - 60, self.height - self.canvas_size[3] - 30))
)
message_frame = Frame(self, width=self.width - 60, height=self.height - self.canvas_size[3] - 30)
message_frame.place(x=15, y=self.canvas_size[3] + 15, anchor=NW)
self.message = Message(message_frame, width=self.width - 60, height=self.height - self.canvas_size[3] - 30)
self.message.pack()
self.message.configure(bg="#edf8ff")
self.configure(bg="#ddeafe")
self.filename = ImageTk.PhotoImage(imim.open("../datas/images/背景@2x.png").resize((self.width, self.canvas_size[3])))
self.check_filename = ImageTk.PhotoImage(Image.open("../datas/images/背景@2x.png").resize((self.width, self.height)))
self.create_image(0, 0, image=self.filename, anchor=NW)
self.chose = self.host_img
self.AllSimObjs = {}
self.receive = None
self.conns = []
self.drawLine = True # 画线标志
self.line_start_obj = None
self.line_end_obj = None
self.line_start_ifs = None
self.line_end_ifs = None
self.chose_obj = None
self.show_label_flag = True
self.show_interface_flag = True
self.check_error_obj = None
self.create_widget()
def is_chose(self):
"""
当被选中时绘制选中框
:return:
"""
self.delete("rectangle")
self.create_rectangle(self.chose_obj.ObjX - 35, self.chose_obj.ObjY - 35, self.chose_obj.ObjX + 15,
self.chose_obj.ObjY + 15, outline="red", tags="rectangle")
self.show_network_config()
if self.chose_obj.ObjType == 2 or self.chose_obj.ObjType == 3:
self.show_router_config()
def tag_bind_event(self):
"""
为每个子组件绑定事件
:return:
"""
def init():
"""
初始化方法将连接对象赋值为初始化值
:return:
"""
self.line_start_obj = None
self.line_end_obj = None
self.line_start_ifs = None
self.line_end_ifs = None
def show_menu(event, tag: SimBase):
"""
右击组件弹出选择接口框
:param event:
:param tag:
:return:
"""
menu = Menu(self, tearoff=0)
flag = False
for conn in tag.connections:
i = tag.connections.index(conn)
if not isinstance(conn, AllSimConnect):
menu.add_command(label=f"接口{i + 1}", command=lambda num=i + 1: interface_selected(num, tag))
flag = True
if not flag:
menu.add_command(label="暂无可用接口", state="disabled")
menu.post(event.x_root, event.y_root)
def interface_selected(interface, tag):
"""
选择接口回调
:param interface:
:return:
"""
if self.line_start_ifs is None:
self.line_start_ifs = interface
self.line_start_obj = tag
self.drawLine = True
self.bind("<Motion>", lambda event: right_motion(event))
self.bind("<Escape>", quit)
self.focus_set() # 获取焦点
else:
self.line_end_ifs = interface
self.line_end_obj = tag
self.delete("Line")
flag = False
if self.line_start_obj.ObjID == self.line_end_obj.ObjID:
messagebox.showerror("注意!", message="不能连接自己")
return
conn = AllSimConnect(self, self.line_start_obj, self.line_start_ifs, self.line_end_obj,
self.line_end_ifs)
conn.draw_line()
for conn_obj in self.line_start_obj.connections: # 判断两个连接对象是否已经连接过了
if conn_obj == conn:
flag = True
if not flag:
self.line_start_obj.connections[self.line_start_ifs - 1] = conn
self.line_end_obj.connections[self.line_end_ifs - 1] = conn
self.message.show_message(f"{self.line_start_obj.ObjLabel}连接{self.line_end_obj.ObjLabel}成功!")
conn.save()
self.conns.append(conn)
init()
self.unbind("<Motion>")
else:
del conn
self.delete("Line")
self.unbind("<Motion>")
init()
messagebox.showerror("注意!", message="已经连接过了")
def right_motion(event):
"""
移动鼠标
:param event:
:param tag:
:return:
"""
if self.drawLine:
self.delete("Line")
x, y = event.x, event.y
if not (0 < x < self.canvas_size[2] and 0 < y < self.canvas_size[3]):
if x < 0:
x = 0
elif x > self.canvas_size[2]:
x = self.canvas_size[2]
if y < 0:
y = 0
elif y > self.canvas_size[3]:
y = self.canvas_size[3]
self.create_line(self.line_start_obj.ObjX, self.line_start_obj.ObjY, x + 8, y + 8, fill="#5b9bd5",
width=1,
tags="Line")
return
self.create_line(self.line_start_obj.ObjX, self.line_start_obj.ObjY, x + 8, y + 8, fill="#5b9bd5",
width=1, tags="Line")
def quit(event):
self.delete("Line") # 删除刚刚产生的连接线
self.drawLine = False # 关闭画线标志
init()
for tag_id, tag in self.AllSimObjs.items():
self.tag_bind(tag.ObjID, "<Button-3>", lambda event, tag=tag: show_menu(event, tag)) # 绑定右击事件
def add_sim_obj(self, component, name):
# todo: 绑定事件
"""
绑定事件
:param component: 组件对象
:param name: 组件名称
"""
def move(event, name):
"""
鼠标左键松开事件
:param event: 事件对象
"""
if 20 + self.canvas_size[0] < event.x < self.canvas_size[2] + 20 and 20 + self.canvas_size[1] < event.y < self.canvas_size[3] - 20: # 在方框内,无变化
if name == "路由器":
tag = SimRouter(self, event.x, event.y)
elif name == "集线器":
tag = SimHub(self, event.x, event.y)
elif name == "交换机":
tag = SimSwitch(self, event.x, event.y)
else:
tag = SimHost(self, event.x, event.y)
tag.create_img()
self.AllSimObjs[tag.ObjID] = tag
tag.save()
self.message.show_message(f"组件 {tag.ObjLabel} 创建成功!")
self.tag_bind_event()
else:
self.delete("L")
def motion(event, name):
"""
鼠标拖动事件
:param event: 事件对象
"""
if name == "路由器":
self.chose = self.router_img
elif name == "集线器":
self.chose = self.hub_img
elif name == "交换机":
self.chose = self.switch_img
else:
self.chose = self.host_img
self.delete("L")
if 20 + self.canvas_size[0] < event.x < self.canvas_size[2] + 20 and 20 + self.canvas_size[1] < event.y < self.canvas_size[3] - 20: # 在方框内,无变化
pass
else: # 在方框外,显示禁止放置标识
self.create_oval(event.x - 10, event.y - 45, event.x + 10, event.y - 25, outline="red", width=2,
tags="L")
self.create_line(event.x - 7, event.y - 42, event.x + 8, event.y - 27, fill="red", width=2, tags="L")
self.create_image(event.x - 30, event.y - 30, image=self.chose, anchor="nw", tags="L")
self.tag_bind(component, "<ButtonRelease-1>", lambda event: move(event, name))
self.tag_bind(component, "<B1-Motion>", lambda event: motion(event, name))
def reload_data(self):
# todo: 加载上一次程序运行的数据
"""
加载上一次程序运行时的数据
:return:
"""
self.AllSimObjs = {}
self.conns = []
sim_obj_sql = "select * from sim_objs"
sim_obj_data = search(sim_obj_sql)
for index, row in sim_obj_data.iterrows(): # 初始化组件对象
sim_type = row["ObjType"]
ObjX = row["ObjX"]
ObjY = row["ObjY"]
ConfigCorrect = row["ConfigCorrect"]
ObjLable = row["ObjLabel"]
ObjID = row["ObjID"]
if sim_type == 1:
tag = SimHost(self, ObjX, ObjY, ObjID, ConfigCorrect, ObjLable)
elif sim_type == 2:
tag = SimRouter(self, ObjX, ObjY, ObjID, ConfigCorrect, ObjLable)
elif sim_type == 3:
tag = SimSwitch(self, ObjX, ObjY, ObjID, ConfigCorrect, ObjLable)
else:
tag = SimHub(self, ObjX, ObjY, ObjID, ConfigCorrect, ObjLable)
tag.create_img()
self.AllSimObjs[tag.ObjID] = tag
sim_conn_sql = "select s.conn_id, ConfigCorrect, node_id, node_ifs from sim_conn s join conn_config c on s.conn_id=c.conn_id"
sim_conn_data = search(sim_conn_sql)
conn_datas = {}
for index, conn in sim_conn_data.iterrows():
if (conn["conn_id"], conn["ConfigCorrect"]) not in conn_datas:
conn_datas[(conn["conn_id"], conn["ConfigCorrect"])] = [(conn["node_id"], conn["node_ifs"])]
else:
conn_datas[(conn["conn_id"], conn["ConfigCorrect"])].append((conn["node_id"], conn["node_ifs"]))
for key, value in conn_datas.items():
conn_obj = AllSimConnect(self, self.AllSimObjs[value[0][0]], value[0][1],
self.AllSimObjs[value[1][0]], value[1][1], key[1])
conn_obj.draw_line()
self.AllSimObjs[value[0][0]].connections[value[0][1] - 1] = conn_obj # 将连接对象传入组件对象
self.AllSimObjs[value[1][0]].connections[value[1][1] - 1] = conn_obj
self.conns.append(conn_obj)
conn_obj.ConfigCorrect = key[1]
self.tag_bind_event()
def show_obj(self, AllSimObj, AllSimConn):
self.AllSimObjs = AllSimObj
self.conns = AllSimConn
for key, sim_obj in self.AllSimObjs.items():
sim_obj.create_img()
for conn in self.conns:
conn.draw_line()
def delete_obj(self):
# todo: 删除对象
"""
选中删除对象
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要删除的对象!")
return
ask = messagebox.askquestion(title='确认操作', message='确认删除该对象吗?')
if ask == "no":
return
self.delete(self.chose_obj.ObjID) # 删除图片
self.delete(self.chose_obj.ObjID + "text") # 删除标签
for conn in self.chose_obj.connections: # 删除该对象的所有连接线
if isinstance(conn, AllSimConnect):
conn.delete_line()
delete_sql = f"delete from sim_conn where conn_id in (select conn_id from conn_config where node_id='{self.chose_obj.ObjID}')"
delete_config_sql = f"delete from conn_config where node_id='{self.chose_obj.ObjID}'"
execute_sql(delete_sql)
execute_sql(delete_config_sql)
delete_obj(self.chose_obj.ObjID)
self.message.show_message(f"组件 {self.chose_obj.ObjLabel} 删除成功!")
self.delete("rectangle")
self.reload_data()
def delete_line(self):
# todo: 删除连接线
"""
删除连接线
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要删除连接线的对象!")
return
conn_sql = f"""
select
s.conn_id, ConfigCorrect, node_id, node_ifs
from sim_conn s
join conn_config c on s.conn_id=c.conn_id
where node_id='{self.chose_obj.ObjID}'
"""
conn_data = search(conn_sql)
conn_names = {}
for index, conn in conn_data.iterrows():
if conn["conn_id"] not in conn_names:
conn_names[conn["conn_id"]] = [(conn["node_id"], conn["node_ifs"])]
else:
conn_names[conn["conn_id"]].append((conn["node_id"], conn["node_ifs"]))
child_d = tk.Toplevel()
child_d.title(f"{self.chose_obj.ObjLabel}的连接线配置")
child_d.geometry('300x200+450+200')
child_d.grab_set()
cv1 = Canvas(child_d)
cv1.pack()
value = StringVar()
combobox = ttk.Combobox(
master=child_d, # 父容器
height=12, # 高度,下拉显示的条目数量
width=15, # 宽度
state='readonly', # readonly(只可选)
font=('', 18), # 字体
textvariable=value, # 通过StringVar设置可改变的值
values=list(conn_names.keys()), # 设置下拉框的选项
)
def del_line():
if value.get() == "":
messagebox.showerror("注意", message="请选择需要删除的连接线!")
return
conn_sql = f"""
select
conn_id, node_id, node_ifs
from conn_config
where conn_id='{value.get()}'
"""
conn_data = search(conn_sql)
delete_sql = f"delete from sim_conn where conn_id='{value.get()}'"
execute_sql(delete_sql)
conn_names = {}
for index, conn in conn_data.iterrows():
if conn["conn_id"] not in conn_names:
conn_names[conn["conn_id"]] = [(conn["node_id"], conn["node_ifs"])]
else:
conn_names[conn["conn_id"]].append((conn["node_id"], conn["node_ifs"]))
for data in conn_names[value.get()]:
self.AllSimObjs[data[0]].connections[data[1] - 1].delete_line()
self.AllSimObjs[data[0]].connections[data[1] - 1] = None
child_d.destroy()
messagebox.showinfo("提示", f"连接线{value.get()}删除成功!")
self.message.show_message(f"连接线{value.get()}删除成功!")
btn_yes = tk.Button(child_d, text='确定', font=('黑体', 12), height=1, command=del_line)
btn_yes.place(x=240, y=20)
combobox.place(x=20, y=20)
def update_tag_name(self):
# todo: 更新组件名称
"""
更新组件名称
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要更新的对象!")
return
child1 = tk.Toplevel()
child1.title(self.chose_obj.ObjLabel + "的标签信息")
child1.geometry('360x150+200+150')
child1.grab_set() # 设置组件焦点抓取。使焦点在释放之前永远保持在这个组件上,只能在这个组件上操作
tk.Label(child1, text='原标签:' + self.chose_obj.ObjLabel,
font=('黑体', 16)).grid(row=0, column=0, columnspan=2, sticky='w')
tk.Label(child1, text='新标签:', font=('黑体', 16)).grid(row=1, column=0, sticky='w') # ,sticky='w'靠左显示
new_name = tk.Entry(child1, font=('黑体', 16), textvariable=tk.StringVar())
new_name.grid(row=1, column=1)
def update_tag():
name = new_name.get()
if name == "":
messagebox.showerror("注意", message="请输入新名称!")
return
self.chose_obj.ObjLabel = name
self.chose_obj.update()
for conn in self.chose_obj.connections:
if isinstance(conn, AllSimConnect):
conn.update_info(self.chose_obj.ObjID)
child1.destroy()
messagebox.showinfo("提示", message="修改成功!")
self.message.show_message(f"{name} 修改名称成功!")
tk.Button(child1, text='确定', font=('黑体', 16), height=1, command=update_tag).grid(row=2, column=0,
sticky='e', pady=10)
tk.Button(child1, text='取消', font=('黑体', 16), height=1, command=child1.destroy).grid(row=2, column=1,
sticky='e', pady=10)
def network_config(self):
# todo: 网络配置
"""
网络配置
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要配置的对象!")
return
if len(self.chose_obj.get_config()) == 0:
messagebox.showerror("注意", message="请先给对象添加连接线!")
return
child_r = tk.Toplevel()
child_r.title(self.chose_obj.ObjLabel + "的网络配置信息")
child_r.geometry('713x522+350+200')
child_r.grab_set() # 设置组件焦点抓取。使焦点在释放之前永远保持在这个组件上,只能在这个组件上操作
ifs_frame = tk.Frame(child_r)
ifs_frame.grid(row=1, column=0, columnspan=4) # 装接口的框架
ifs_frame_YN = tk.Frame(child_r)
ifs_frame_YN.grid(row=2, column=0, columnspan=4)
num = 0
datas = {}
for conn in self.chose_obj.connections:
if isinstance(conn, AllSimConnect):
index = self.chose_obj.connections.index(conn)
num_label = tk.LabelFrame(ifs_frame, text=f'接口{index + 1}')
num_label.grid(row=num, column=0, padx=18, ipady=5)
tk.Label(num_label, text='MAC:', font=('黑体', 16)).grid(row=0, column=0)
mac_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar(), state=DISABLED if self.chose_obj.ObjType not in [1, 2, 3] else NORMAL)
mac_en.insert('0', str(self.chose_obj.interface[index].get("mac", "")))
mac_en.grid(row=0, column=1, padx=10)
tk.Label(num_label, text='IP:', font=('黑体', 16)).grid(row=1, column=0)
ip_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar(), state=DISABLED if self.chose_obj.ObjType not in [1, 2] else NORMAL)
ip_en.insert('0', str(self.chose_obj.interface[index].get("ip", "")))
ip_en.grid(row=1, column=1, padx=10)
tk.Label(num_label, text='端口:', font=('黑体', 16)).grid(row=0, column=2)
port_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar(), state=DISABLED if self.chose_obj.ObjType != 1 else NORMAL)
port_en.insert('0', str(self.chose_obj.interface[index].get("conn_port", "")))
port_en.grid(row=0, column=3, padx=10)
tk.Label(num_label, text='应用层地址:', font=('黑体', 16)).grid(row=1, column=2)
addr_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar(), state=DISABLED if self.chose_obj.ObjType != 1 else NORMAL)
addr_en.insert('0', str(self.chose_obj.interface[index].get("addr", "")))
addr_en.grid(row=1, column=3, padx=10)
num += 1
datas[index + 1] = {"mac": mac_en, "ip": ip_en, "conn_port": port_en, "addr": addr_en}
num_label = tk.LabelFrame(ifs_frame, text=f'示例')
num_label.grid(row=num, column=0, padx=18, ipady=5)
tk.Label(num_label, text='MAC:', font=('黑体', 16)).grid(row=0, column=0)
mac_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar())
mac_en.insert('0', "MAC11")
mac_en.config(state=READONLY)
mac_en.grid(row=0, column=1, padx=10)
tk.Label(num_label, text='IP:', font=('黑体', 16)).grid(row=1, column=0)
ip_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar())
ip_en.insert(0, "10.1.1.10")
ip_en.config(state=READONLY)
ip_en.grid(row=1, column=1, padx=10)
tk.Label(num_label, text='端口:', font=('黑体', 16)).grid(row=0, column=2)
port_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar())
port_en.insert('0', "80")
port_en.config(state=READONLY)
port_en.grid(row=0, column=3, padx=10)
tk.Label(num_label, text='应用层地址:', font=('黑体', 16)).grid(row=1, column=2)
addr_en = tk.Entry(num_label, font=('黑体', 16), textvariable=tk.StringVar())
addr_en.insert('0', "10.1.2.10:10810:Name3")
addr_en.config(state=READONLY)
addr_en.grid(row=1, column=3, padx=10)
def commit():
self.chose_obj.config(datas)
self.message.show_message(f"组件 {self.chose_obj.ObjLabel} 网络配置成功!")
child_r.destroy()
tk.Button(ifs_frame_YN, text='确定', font=('黑体', 16), height=1, command=commit).grid(row=0, column=0,
padx=20, pady=20) # ,sticky="w"
tk.Button(ifs_frame_YN, text='取消', font=('黑体', 16), height=1,
command=child_r.destroy).grid(row=0, column=2, padx=20, pady=20)
def router_table_config(self):
# todo: 路由表配置
"""
路由表配置
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要配置的对象!")
return
if self.chose_obj.ObjType != 2:
messagebox.showerror("注意", message="请选择路由器对象!")
return
RouterConfigWindow(self, self.chose_obj)
def mac_table_config(self):
# todo: 交换表配置
"""
交换表配置
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要配置的对象!")
return
if self.chose_obj.ObjType != 3:
messagebox.showerror("注意", message="请选择交换机对象!")
return
SwitchConfigWindow(self, self.chose_obj)
def show_label(self):
"""
显示/不显示标签
:return:
"""
self.show_label_flag = not self.show_label_flag
if self.show_label_flag:
for tag in self.AllSimObjs.values():
tag.create_img()
else:
for tag in self.AllSimObjs.values():
self.delete(tag.ObjID + "text")
def show_interface(self):
# todo: 显示/不显示接口
"""
显示/不显示接口
:return:
"""
self.show_interface_flag = not self.show_interface_flag
if self.show_interface_flag:
for conn in self.conns:
conn.draw_line()
else:
for conn in self.conns:
self.delete(conn.NobjS.ObjID + conn.NobjE.ObjID)
def show_network_config(self):
# todo: 显示网络配置信息
"""
显示网络配置信息
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要显示的对象!")
return
self.delete("netSet")
self.create_text(self.width * 0.82 + 120, 80, text="(" + self.chose_obj.ObjLabel + ")", anchor="n", font=('微软雅黑', 14, 'bold'),
fill="#7030a0", tags="netSet")
self.create_text(self.width * 0.82 + 20, 80 + 25, text=self.chose_obj,
anchor="nw", font=('宋体', 14), tags="netSet")
def show_router_config(self):
# todo: 显示路由表交换表信息
"""
显示路由交换表信息
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要显示的对象!")
return
if self.chose_obj.ObjType != 2 and self.chose_obj.ObjType != 3:
messagebox.showerror("注意", message="请选择路由器/交换机对象!")
return
self.delete("routerSet")
self.create_text(self.width * 0.82 + 120, self.canvas_size[3] / 2 + 50, text="(" + self.chose_obj.ObjLabel + ")", anchor="n", font=('微软雅黑', 14, 'bold'),
fill="#7030a0", tags="routerSet")
self.create_text(self.width * 0.82 + 20, self.canvas_size[3] / 2 + 50 + 25, text=self.chose_obj.get_table_config(),
anchor="nw", font=('宋体', 14), tags="routerSet")
def send_packet(self):
"""
发送数据包
:return:
"""
if self.chose_obj is None:
messagebox.showerror("注意", message="请先选择要显示的对象!")
return
if self.chose_obj.ConfigCorrect != 1:
messagebox.showerror("注意", message="请先对选择对象进行网络配置!")
return
if self.chose_obj.ObjType != 1:
messagebox.showerror("注意", message="请选择主机对象!")
return
child2 = tk.Toplevel()
child2.title("数据包配置")
child2.geometry('330x195+200+110')
child2.grab_set() # 设置组件焦点抓取。使焦点在释放之前永远保持在这个组件上,只能在这个组件上操作
tk.Label(child2, text='目的IP:', font=('黑体', 16)).grid(row=0, column=0, columnspan=2, sticky='w', pady=10)
packet_ip = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_ip.grid(row=0, column=1, pady=10)
tk.Label(child2, text='消息:', font=('黑体', 16)).grid(row=1, column=0, sticky='w', pady=10) # ,sticky='w'靠左显示
packet_message = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_message.grid(row=1, column=1, pady=10)
def send():
"""
发送数据包
:return:
"""
if packet_ip.get() == "":
messagebox.showerror("注意", message="ip地址不能为空")
return
if not validate_ip_address(packet_ip.get()):
messagebox.showerror("注意", message="IP地址不规范")
return
if packet_message.get() == "":
messagebox.showerror("注意", message="消息不能为空!")
return
ip = packet_ip.get()
message = packet_message.get()
child2.destroy()
self.chose_obj.create_packet(ip,
None,
message)
tk.Button(child2, text='确定', font=('黑体', 16), height=1, command=send).grid(row=3, column=0, sticky='e', pady=10)
tk.Button(child2, text='取消', font=('黑体', 16), height=1, command=child2.destroy).grid(row=3, column=1, sticky='e', pady=10)
def send_packet_list(self):
"""
批量发送数据包
:return:
"""
hosts = {}
for tag in self.AllSimObjs.values():
if tag.ObjType == 1 and tag.ConfigCorrect == 1:
hosts[tag.ObjLabel] = tag.ObjID
child2 = tk.Toplevel()
child2.title("批量数据包配置")
child2.geometry('462x452+200+110')
tk.Label(child2, text='目的IP:', font=('黑体', 16)).grid(row=0, column=0, columnspan=2, sticky='w', ipady=10)
packet_ip = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_ip.grid(row=0, column=1, pady=5)
tk.Label(child2, text='消息:', font=('黑体', 16)).grid(row=1, column=0, sticky='w', pady=5) # ,sticky='w'靠左显示
packet_message = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_message.grid(row=1, column=1, pady=5)
host = StringVar()
tk.Label(child2, text='发送主机:', font=('黑体', 16)).grid(row=2, column=0, sticky='w',
pady=5) # ,sticky='w'靠左显示
combobox = ttk.Combobox(
master=child2, # 父容器
height=5, # 高度,下拉显示的条目数量
width=12, # 宽度
state='readonly', # readonly(只可选)
font=('', 16), # 字体
textvariable=host, # 通过StringVar设置可改变的值
values=list(hosts.keys()), # 设置下拉框的选项
)
combobox.grid(row=2, column=1, pady=5)
packet_frame = tk.Frame(child2)
packet_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
packet_treeview = ttk.Treeview(packet_frame, columns=("source_host", "ip", "mac", "message"), show="headings")
packet_treeview.heading("source_host", text="发送主机")
packet_treeview.column("source_host", width=60, anchor=CENTER)
packet_treeview.heading("ip", text="IP")
packet_treeview.column("ip", width=120, anchor=CENTER)
packet_treeview.heading("mac", text="MAC")
packet_treeview.column("mac", width=60, anchor=CENTER)
packet_treeview.heading("message", text="消息")
packet_treeview.column("message", width=120, anchor=CENTER)
packet_treeview.pack(side="left", fill="both")
scrollbar = ttk.Scrollbar(packet_frame, orient="vertical", command=packet_treeview.yview)
scrollbar.pack(side="right", fill="y")
packet_treeview.configure(yscrollcommand=scrollbar.set)
packets = []
def add():
ip = packet_ip.get()
message = packet_message.get()
chose_host = host.get()
if ip == "" or message == "" or chose_host == "":
messagebox.showerror("注意", message="输入框不能为空")
return
packet = SimPacket(self.AllSimObjs[hosts[chose_host]].interface[0]["ip"],
self.AllSimObjs[hosts[chose_host]].interface[0]["mac"],
ip, None, message)
packets.append((self.AllSimObjs[hosts[chose_host]], packet))
packet_treeview.delete(*packet_treeview.get_children())
for datas in packets:
tag: SimBase = datas[0]
packet_data: SimPacket = datas[1]
packet_treeview.insert("", "end", values=(
tag.ObjLabel, packet_data.destination_ip, packet_data.destination_mac, packet_data.message))
def send():
if len(packets) == 0:
messagebox.showerror("注意", message="请至少添加一条数据包!")
return
for data in packets:
threading.Thread(target=data[0].send, args=(data[1],)).start()
child2.destroy()
tk.Button(child2, text="添加数据包", font=('黑体', 14), height=3, command=add).grid(row=0, column=2, rowspan=4, padx=10)
button_frame = Frame(child2)
tk.Button(button_frame, text="发送", font=('黑体', 16), height=1, command=send).pack(side=RIGHT, padx=20)
tk.Button(button_frame, text="取消", font=('黑体', 16), height=1, command=child2.destroy).pack(side=RIGHT)
button_frame.grid(row=6, column=0, columnspan=3)
def clear_canvas(self):
"""
清除画布
:return:
"""
ask = messagebox.askquestion(title='确认操作', message='确认要清除画布吗?')
if ask == "no":
return
truncate_db() # 清除数据库
for tag_id, tag in self.AllSimObjs.items():
self.delete(tag_id)
self.delete(tag_id + "text")
for conn in self.conns:
conn.delete_line()
self.delete("rectangle")
self.AllSimObjs.clear()
self.conns.clear()
def export_data(self):
try:
export = ExportUtil(sys.path[0] + "/database.xlsx")
export.export()
self.message.show_message("文件导出成功!文件位置在{}".format(sys.path[0] + "/database.xlsx"))
except Exception as E:
self.message.show_message(str(E), color="red")
def import_data(self):
truncate_db()
for tag_id, tag in self.AllSimObjs.items():
self.delete(tag_id)
self.delete(tag_id + "text")
for conn in self.conns:
conn.delete_line()
self.delete("rectangle")
self.AllSimObjs.clear()
self.conns.clear()
file_path = filedialog.askopenfilename()
if file_path:
export = ExportUtil(file_path)
export.import_data()
self.message.show_message("文件导入成功!")
self.reload_data()
def check_network(self):
"""
校验
:return:
"""
hosts = {}
for key, tag in self.AllSimObjs.items():
if tag.ObjType == 1 and tag.ConfigCorrect == 1:
hosts[tag.ObjLabel] = tag.ObjID
child2 = tk.Toplevel()
child2.title("数据包配置")
child2.geometry('392x168+200+110')
child2.grab_set() # 设置组件焦点抓取。使焦点在释放之前永远保持在这个组件上,只能在这个组件上操作
tk.Label(child2, text='发送主机:', font=('黑体', 16)).grid(row=0, column=0, columnspan=2, sticky='w', pady=10)
send_host = StringVar()
host_combobox = ttk.Combobox(
master=child2, # 父容器
height=5, # 高度,下拉显示的条目数量
width=18, # 宽度
state='readonly', # readonly(只可选)
font=('', 16), # 字体
textvariable=send_host, # 通过StringVar设置可改变的值
values=list(hosts.keys()), # 设置下拉框的选项
)
host_combobox.grid(row=0, column=1, pady=10)
tk.Label(child2, text='接收主机:', font=('黑体', 16)).grid(row=1, column=0, sticky='w',
pady=10) # ,sticky='w'靠左显示
receive_host = StringVar()
ttk.Combobox(
master=child2, # 父容器
height=5, # 高度,下拉显示的条目数量
width=18, # 宽度
state='readonly', # readonly(只可选)
font=('', 16), # 字体
textvariable=receive_host, # 通过StringVar设置可改变的值
values=list(hosts.keys()), # 设置下拉框的选项
).grid(row=1, column=1, pady=10)
def check():
"""
发送数据包
:return:
"""
if send_host.get() == "" or receive_host.get() == "":
messagebox.showerror("注意", message="信息不能为空")
return
if send_host.get() == receive_host.get():
messagebox.showerror("注意", message="发送主机和接收主机不能相同!")
send_host_obj: SimHost = self.AllSimObjs[hosts[send_host.get()]]
receive_host_obj: SimHost = self.AllSimObjs[hosts[receive_host.get()]]
child2.destroy()
send_host_obj.create_packet(receive_host_obj.interface[0]["ip"], receive_host_obj.interface[0]["mac"], "ping", True)
TransferAnimate(self, self.receive == receive_host_obj)
if self.receive == receive_host_obj:
self.message.show_message("校验成功:{}{} 能正常连通".format(send_host_obj.ObjLabel, receive_host_obj.ObjLabel))
else:
self.message.show_message(
"校验成功:{}{} 无法正常连通,请检查一下组件 {} 的配置".format(send_host_obj.ObjLabel, receive_host_obj.ObjLabel, self.check_error_obj.ObjLabel), "red")
self.check_error_obj = None
self.receive = None
tk.Button(child2, text='校验', font=('黑体', 16), height=1, command=check).grid(row=5, column=0, sticky='e',
pady=10)
tk.Button(child2, text='取消', font=('黑体', 16), height=1, command=child2.destroy).grid(row=5, column=1,
sticky='e', pady=10)
def create_config_button(self):
font_size = 16
font_style = ("Arial", font_size)
style = ttk.Style()
style.configure("TMenubutton", font=font_style)
# 创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tk.Menu(root, font=font_style)
# 定义一个空菜单单元
setMenu = tk.Menu(menubar, tearoff=0, font=font_style)
menubar.add_cascade(label='删除与修改', menu=setMenu, font=font_style)
setMenu.add_command(label='删除对象', command=self.delete_obj)
setMenu.add_command(label='删除连接线', command=self.delete_line)
setMenu.add_command(label='修改标签', command=self.update_tag_name)
# # 定义一个空菜单单元
setMenu = tk.Menu(menubar, tearoff=0, font=font_style)
menubar.add_cascade(label='基础配置', menu=setMenu, font=font_style)
setMenu.add_command(label='网络配置', command=self.network_config)
setMenu.add_command(label='路由表配置', command=self.router_table_config)
setMenu.add_command(label='交换表配置', command=self.mac_table_config)
root.config(menu=menubar)
# 定义一个空菜单单元
setMenu = tk.Menu(menubar, tearoff=0, font=font_style)
menubar.add_cascade(label='显示设置', menu=setMenu, font=font_style)
setMenu.add_command(label='显示/不显示标签', command=self.show_label)
setMenu.add_command(label='显示/不显示接口', command=self.show_interface)
setMenu.add_command(label='显示网络配置信息', command=self.show_network_config)
setMenu.add_command(label='显示路由/交换表信息', command=self.show_router_config)
# 定义一个空菜单单元
setMenu = tk.Menu(menubar, tearoff=0, font=font_style)
menubar.add_cascade(label='发送数据包', menu=setMenu, font=font_style)
setMenu.add_command(label='发送数据包', command=self.send_packet)
setMenu.add_command(label='批量发送数据包', command=self.send_packet_list)
menubar.add_command(label='清除屏幕', command=self.clear_canvas, font=font_style)
menubar.add_command(label='导出数据', command=self.export_data, font=font_style)
menubar.add_command(label='导入数据', command=self.import_data, font=font_style)
menubar.add_command(label='校验', command=self.check_network, font=font_style)
# 设置字体大小
for menu in menubar.winfo_children():
menu.config(font=font_style)
for item in menu.winfo_children():
item.config(font=font_style)
root.config(menu=menubar)
def create_widget(self):
"""
创建整体页面布局
:return:
"""
self.create_rectangle(self.canvas_size[0], self.canvas_size[1], self.canvas_size[2], self.canvas_size[3], outline="#7f6000", width=0) # 矩形框,左上角坐标,右下角坐标
self.create_image(self.width * 0.82, 30, image=self.label_top_img, anchor=NW) # 矩形框,左上角坐标,右下角坐标
self.create_text(self.width * 0.82 + 120, 30 + 15, text="网络配置信息", anchor="n", font=('微软雅黑', 18, 'bold'))
self.create_image(self.width * 0.82, self.canvas_size[3] / 2, image=self.label_bottom_img, anchor=NW) # 矩形框,左上角坐标,右下角坐标
# round_rectangle(self, self.width * 0.82, self.canvas_size[3] / 2, self.width * 0.98, self.canvas_size[3] - 30, outline="#ffff00", width=2, fill="#f4b88e") # 矩形框,左上角坐标,右下角坐标
self.create_text(self.width * 0.82 + 120, self.canvas_size[3] / 2 + 15, text="路由/交换表信息", anchor="n", font=('微软雅黑', 18, 'bold'))
# 显示左边的固定图片
img_height, text_height, split_width = 50, 40, 120
self.create_text(text_height, split_width + 40, text="路由器", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
router = self.create_image(img_height, split_width, image=self.router_img, anchor="nw")
self.create_text(text_height, split_width * 2 + 40, text="交换机", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
switch = self.create_image(img_height, split_width * 2, image=self.switch_img, anchor="nw")
self.create_text(text_height, split_width * 3 + 40, text="集线器", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
hub = self.create_image(img_height, split_width * 3, image=self.hub_img, anchor="nw")
self.create_text(text_height, split_width * 4 + 40, text="主机", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
host = self.create_image(img_height, split_width * 4, image=self.host_img, anchor="nw")
self.add_sim_obj(router, "路由器")
self.add_sim_obj(switch, "交换机")
self.add_sim_obj(hub, "集线器")
self.add_sim_obj(host, "主机")
if __name__ == '__main__':
root = Window()
root.title('网络拓扑图')
screen_width = root.winfo_screenwidth() # winfo 方法来获取当前电脑屏幕大小
screen_height = root.winfo_screenheight()
root_attr = {
"width": screen_width * 0.83,
"height": screen_height * 0.85,
}
size = '%dx%d+%d+%d' % (root_attr['width'], root_attr['height'], (screen_width - root_attr['width']) / 2,
(screen_height - root_attr['height']) / 2 - 30)
canvas = NetWorkAnalog(root, width=root_attr['width'], heigh=root_attr['height'], bg="white")
canvas.place(x=0, y=0, anchor='nw')
canvas.create_config_button()
canvas.reload_data()
root.geometry(size)
root.mainloop()

@ -0,0 +1,795 @@
import math
import sys
import threading
from time import sleep
from tkinter import Tk
from ttkbootstrap import *
from uuid import uuid4
import ipaddress
from PIL import ImageTk, Image
from dbUtil import search, execute_sql
class SimBase():
# todo: 组件父类
"""
图标类所有组件的父类
"""
def __init__(self, canvas, x, y, id, config=None, label=None):
self.ConfigCorrect = 0 if config is None else config # 是否进行配置
self.ObjType = None # 组件类型 1->主机2->路由器3->交换机4->集线器
self.ObjLabel = ""
self.ObjID = id
self.ObjX = x
self.ObjY = y
self.canvas = canvas
self.host_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机@2x.png").resize((40, 40)))
self.host_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机--暗色@2x.png").resize((40, 40)))
self.router_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/路由器@2x.png").resize((40, 40)))
self.router_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/路由器--暗色@2x.png").resize((40, 40)))
self.switch_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/交换机@2x.png").resize((40, 40)))
self.switch_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/交换机--暗色@2x.png").resize((40, 40)))
self.hub_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/集线器@2x.png").resize((40, 40)))
self.hub_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/集线器--暗色@2x.png").resize((40, 40)))
self.img = None
self.img_tm = None
self.interface = [{}, {}, {}, {}]
self.connections = ["1", "2", "3", "4"]
self.set_default_config()
def bind_event(self):
self.canvas.tag_bind(self.ObjID, "<Button-1>", self.start_drag)
self.canvas.tag_bind(self.ObjID, "<B1-Motion>", self.drag)
self.canvas.tag_bind(self.ObjID, "<ButtonRelease-1>", self.release)
def set_default_name(self):
data_frame = search(f"select objid from sim_objs where objType={self.ObjType}")
num = data_frame.size + 1
if isinstance(self, SimHost):
name = "SHO%d" % num
elif isinstance(self, SimRouter):
name = "SRO%d" % num
elif isinstance(self, SimSwitch):
name = "SWI%d" % num
else:
name = "SHUB%d" % num
return name
def release(self, event):
if self.click_x == event.x and self.click_y == event.y: # 鼠标左键单击
self.canvas.chose_obj = self
self.canvas.is_chose()
else:
self.update()
def start_drag(self, event):
self.canvas.tag_raise(self.ObjID) # 将 SimBase 组件置于最上层
self.start_x = event.x
self.start_y = event.y
self.click_x = event.x
self.click_y = event.y
def drag(self, event):
"""
移动图标
:param event:
:return:
"""
self.canvas.delete("rectangle")
self.canvas.chose_obj = None
dx = event.x - self.start_x
dy = event.y - self.start_y
# 移动范围限制, 超出移动范围则直接返回
if not (self.canvas.canvas_size[0] + 20 <= self.ObjX + dx <= self.canvas.canvas_size[2] - 20 and 20 + self.canvas.canvas_size[1] <= self.ObjY + dy <= self.canvas.canvas_size[3] - 20):
return
self.ObjX += dx
self.ObjY += dy
self.canvas.move(self.ObjID, dx, dy) # 移动 SimBase 组件
self.canvas.move(self.ObjID + "text", dx, dy) # 移动 SimBase 组件
self.start_x = event.x
self.start_y = event.y
for conn in self.connections:
if isinstance(conn, AllSimConnect):
conn.update_line()
def create_img(self):
"""
创建图片
:return:
"""
if self.ObjType == 1:
self.img = self.host_img
self.img_tm = self.host_img_tm
elif self.ObjType == 2:
self.img = self.router_img
self.img_tm = self.router_img_tm
elif self.ObjType == 3:
self.img = self.switch_img
self.img_tm = self.switch_img_tm
else:
self.img = self.hub_img
self.img_tm = self.hub_img_tm
self.canvas.delete("L")
id = self.canvas.create_image(self.ObjX - 30, self.ObjY - 30,
image=self.img if self.ConfigCorrect == 1 else self.img_tm, anchor="nw",
tags=self.ObjID)
self.canvas.dtag("L", "L")
self.canvas.create_text(self.ObjX - 20, self.ObjY - 60, text=self.ObjLabel, font=("", 16, "bold"),
fill="#9b78eb", tags=self.ObjID + "text", anchor="nw")
self.canvas.tag_raise(id)
self.bind_event()
def config(self, interface):
"""
网络配置方法
:param interface: 传入配置数据
:return:
"""
for key, value in interface.items():
self.interface[key - 1] = {key: value.get() if not value.get() == "" else "NULL" for key, value in value.items()}
self.ConfigCorrect = 1
self.create_img()
for conn in self.connections:
if isinstance(conn, AllSimConnect):
index = self.connections.index(conn) + 1
conn.update_node_config(self, index)
self.update()
def set_default_config(self):
sql = f"select * from conn_config where node_id='{self.ObjID}'"
conn_data = search(sql)
for index, conn in conn_data.iterrows():
self.interface[int(conn["node_ifs"]) - 1] = {"ip": conn["ip"],
"mac": conn["mac"],
"conn_port": conn["conn_port"],
"addr": conn["addr"]}
def get_config(self):
sql = f"select * from conn_config where node_id='{self.ObjID}'"
conn_data = search(sql)
return conn_data
def save(self):
"""
将对象存储至mysql当中
:return:
"""
sql = f"insert into sim_objs values ('{self.ObjID}', {self.ObjType}, '{self.ObjLabel}'," \
f"{self.ObjX}, {self.ObjY}, {self.ConfigCorrect})"
execute_sql(sql)
def update(self):
"""
当坐标发生改变时修改数据库数据
:return:
"""
self.canvas.delete(self.ObjID + "text")
self.canvas.create_text(self.ObjX - 20, self.ObjY - 60, text=self.ObjLabel, font=("", 16, "bold"),
fill="#7030a0", tags=self.ObjID + "text", anchor="nw")
sql = f"update sim_objs set objLabel='{self.ObjLabel}', ObjX={self.ObjX}," \
f"ObjY={self.ObjY}, ConfigCorrect={self.ConfigCorrect} where ObjID='{self.ObjID}'"
execute_sql(sql)
def transfer_animate(self, status, packet, error_message=None):
if status:
text = f"目的IP: {str(packet.destination_ip)}\n" \
f"目的MAC: {packet.destination_mac}\n" \
f"消息内容: {packet.message}"
self.canvas.create_rectangle(self.ObjX + 30, self.ObjY - 30, self.ObjX + 160, self.ObjY + 20, outline="#92d050",
width=3, fill="#92d050", tags=self.ObjID + "packetData")
self.canvas.create_text(self.ObjX + 35, self.ObjY - 25, text=text, anchor="nw",
font=('', 10), tags=self.ObjID + "packetData") # 显示文字
self.canvas.update()
sleep(2)
self.canvas.delete(self.ObjID + "packetData") # 删除展示的数据包内容
else:
text = f"传输失败\n" if error_message is None else error_message
self.canvas.create_rectangle(self.ObjX + 30, self.ObjY - 30, self.ObjX + 160, self.ObjY, outline="red",
width=3, fill="red", tags=self.ObjID + "packetData")
self.canvas.create_text(self.ObjX + 35, self.ObjY - 25, text=text, anchor="nw",
font=('', 10), tags=self.ObjID + "packetData") # 显示文字
self.canvas.update()
sleep(2)
self.canvas.delete(self.ObjID + "packetData") # 删除展示的数据包内容
def __str__(self):
str = ""
config = self.get_config()
for index, data in config.iterrows():
str += f"【接口{data['node_ifs']}\n"
str += f"IP: {data['ip']}\n"
str += f"MAC: {data['mac']}\n"
return str
class SimPacket():
# todo: 数据包类
"""
数据包类
"""
def __init__(self, source_ip, source_mac, destination_ip, destination_mac, message, ping=False):
"""
:param source_mac: 源主机mac地址
:param source_ip: 源主机ip地址
:param destination_mac: 目的主机mac地址
:param destination_ip: 目的主机ip地址
:param message: 数据
"""
self.source_mac = source_mac
self.source_ip = source_ip
self.destination_mac = destination_mac
self.destination_ip = destination_ip
self.message = message
self.up_jump = None # 上一跳连接对象
self.ping = ping
self.flag = False
self.img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/packet.png").resize((30, 30)))
self.id = str(uuid4())
def move(self, cv, target_x, target_y, duration):
start_x, start_y = cv.coords(self.id)
distance_x = target_x - start_x
distance_y = target_y - start_y
steps = duration // 10 # 以10毫秒为间隔进行移动
step_x = distance_x / steps
step_y = distance_y / steps
self._move_step(cv, start_x, start_y, target_x, target_y, step_x, step_y, steps)
def _move_step(self, cv, start_x, start_y, target_x, target_y, step_x, step_y, steps):
if steps > 0:
new_x = start_x + step_x
new_y = start_y + step_y
cv.coords(self.id, new_x, new_y)
cv.update() # 更新画布显示
sleep(0.01) # 添加延迟以控制动画速度
self._move_step(cv, new_x, new_y, target_x, target_y, step_x, step_y, steps - 1)
else:
cv.coords(self.id, target_x, target_y)
cv.delete(self.id)
def transfer_packet(self, cv: Canvas, nodex_tag: SimBase, nodey_tag: SimBase):
if self.ping:
return
cv.create_image(nodex_tag.ObjX - 15, nodex_tag.ObjY - 15, image=self.img, anchor="nw", tags=self.id)
self.move(cv, nodey_tag.ObjX - 15, nodey_tag.ObjY - 15, 500)
class AllSimConnect():
# todo: 连接类
def __init__(self, canvas, nodex: SimBase, nodex_ifs, nodey: SimBase, nodey_ifs, config=None):
"""
连接对象
:param nodex: 节点
:param nodex_ifs: 节点接口
:param nodey: 节点
:param nodey_ifs: 节点接口
"""
self.canvas = canvas
self.ConfigCorrect = 0 if config is None else config
self.NobjS = nodex
self.NobjE = nodey
self.IfsS = nodex_ifs
self.IfsE = nodey_ifs
self.width = False if self.ConfigCorrect == 0 else True # 线的粗细
def is_connected_to(self, other):
"""
判断两个连接对象是否已经连接
:param other: 另一个连接对象
:return: 如果已连接则返回True否则返回False
"""
return (
self.NobjS.ObjID == other.NobjS.ObjID
and self.NobjE.ObjID == other.NobjE.ObjID
)
def update_node_config(self, node, ifs):
"""
当节点进行网络配置后将节点的接口配置保存
:return:
"""
try:
nodex_update_sql = f"""
update conn_config set
ip='{node.interface[ifs - 1]["ip"]}',
mac='{node.interface[ifs - 1]["mac"]}'
"""
if not node.interface[ifs - 1]["conn_port"] == "NULL":
nodex_update_sql += f"""
,conn_port='{int(node.interface[ifs - 1]["conn_port"])}'
"""
if not node.interface[ifs - 1]["addr"] == "NULL":
nodex_update_sql += f"""
,addr='{node.interface[ifs - 1]["addr"]}'
"""
nodex_update_sql += f"""
where node_id='{node.ObjID}' and node_ifs={ifs}
"""
execute_sql(nodex_update_sql)
self.ConfigCorrect = 1
self.check_config()
update_sql = f"""
update sim_conn set ConfigCorrect={self.ConfigCorrect}
where conn_id in (
select distinct conn_id from conn_config where node_id='{node.ObjID}'
)
"""
execute_sql(update_sql)
except Exception as E:
print(E)
self.canvas.message.show_message(f"{E}")
def check_config(self):
"""
检查两边节点的配置是否正确
:return:
"""
if self.NobjS.interface[self.IfsS - 1]["mac"] != "" and self.NobjS.interface[self.IfsS - 1][
"ip"] != "" \
and self.NobjE.interface[self.IfsE - 1]["mac"] != "" and self.NobjE.interface[self.IfsE - 1][
"ip"] != "":
self.width = 4
self.draw_line()
else:
self.width = 1
self.draw_line()
def transfer(self, source_node, packet: SimPacket):
"""
传输数据
:param packet: 数据包
:return:
"""
if source_node == self.NobjS:
if not packet.ping:
packet.transfer_packet(self.canvas, self.NobjS, self.NobjE)
self.NobjE.receive(packet)
else:
packet.transfer_packet(self.canvas, self.NobjE, self.NobjS)
self.NobjS.receive(packet)
def draw_line(self):
if self.width:
line = self.canvas.create_line(self.NobjS.ObjX, self.NobjS.ObjY, self.NobjE.ObjX, self.NobjE.ObjY,
width=2, fill="#c372f0", tags=self.NobjS.ObjID + self.NobjE.ObjID + "line")
else:
line = self.canvas.create_line(self.NobjS.ObjX, self.NobjS.ObjY, self.NobjE.ObjX, self.NobjE.ObjY,
width=2, dash=(250, 4), fill="#c372f0", tags=self.NobjS.ObjID + self.NobjE.ObjID + "line")
self.canvas.tag_lower(line, 2)
self.analyseIFS(self.NobjS.ObjX, self.NobjS.ObjY, self.NobjS.ObjLabel, self.IfsS,
self.NobjE.ObjX, self.NobjE.ObjY, self.NobjE.ObjLabel, self.IfsE)
def update_line(self):
"""
当组件移动时重新绘制线
:return:
"""
self.canvas.delete(self.NobjS.ObjID + self.NobjE.ObjID + "line")
self.canvas.delete(self.NobjS.ObjID + self.NobjE.ObjID)
self.draw_line()
def update_info(self, obj_id):
"""
修改数据库中的连接信息
:return:
"""
update_sql = f"""
update sim_conn set conn_id='{self.NobjS.ObjLabel}-{self.NobjE.ObjLabel}', ConfigCorrect={self.ConfigCorrect}
where conn_id in (
select distinct conn_id from conn_config where node_id='{obj_id}'
)
"""
execute_sql(update_sql)
def analyseIFS(self, SX, SY, SLabel, IfsS, EX, EY, ELabel, IfsE): # NobjS的x,y;NobjE的x,y; #分析接口在哪个位置,再显示
'''
:param SX: S对象的x坐标
:param SY: S对象的y坐标
:param SLabel: S对象的标签
:param IfsS: S对象要显示的接口号
'''
offset = 15
if (EX - SX) == 0: # 即垂直的时候,NobjS在NobjE对象的正上方和正下方x坐标无变化只需要y变化
R = 18
x = 0 # x无偏移量
y = R
else:
k = (EY - SY) / (EX - SX) # ey-sy/sx-ex
reat = math.atan(k) # 根据斜率计算弧度
# 连线与图标交接点坐标
R = 18
x = abs(math.cos(reat) * R) + 6 # python math中三角函数中的数值是弧度而计算器中的数值是角度
y = abs(math.sin(reat) * R) + 6
if SX <= EX and SY <= EY: # NobjS在NobjE的左上角NobjS的右下角连接NobjE的左上角
x_S = SX + x
y_S = SY + y # NobjS的连接点坐标
x_E = EX - x
y_E = EY - y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text((x_S + offset, y_S - offset), text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E - offset, y_E - offset, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
elif SX < EX and SY > EY: # NobjS在NobjE的左下角NobjS的右上角连接NobjE的左下角
x_S = SX + x
y_S = SY - y # NobjS的连接点坐标
x_E = EX - x
y_E = EY + y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text(x_S + offset, y_S - offset, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E - offset, y_E, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
elif SX > EX and SY < EY: # NobjS在NobjE的右上角NobjS的左下角连接NobjE的右上角
x_S = SX - x
y_S = SY + y # NobjS的连接点坐标
x_E = EX + x
y_E = EY - y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text(x_S - offset, y_S, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E + offset, y_E, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
elif SX >= EX and SY >= EY: # NobjS在NobjE的右下角NobjS的左上角连接NobjE的右下角
x_S = SX - x
y_S = SY - y # NobjS的连接点坐标
x_E = EX + x
y_E = EY + y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text(x_S - offset, y_S - offset, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E + offset, y_E - offset, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
def save(self):
"""
将连接对象保存至数据库
:return:
"""
conn_id = self.NobjS.ObjLabel + "-" + self.NobjE.ObjLabel
sql = f"insert into sim_conn values ('{conn_id}', {self.ConfigCorrect})"
execute_sql(sql)
execute_sql(
f"insert into conn_config values ('{conn_id}', '{self.NobjS.ObjID}', {self.IfsS}, '', '', '', '')")
execute_sql(
f"insert into conn_config values ('{conn_id}', '{self.NobjE.ObjID}', {self.IfsE}, '', '', '', '')")
def delete_line(self):
self.canvas.delete(self.NobjS.ObjID + self.NobjE.ObjID)
self.canvas.delete(self.NobjS.ObjID + self.NobjE.ObjID + "line")
def __eq__(self, other):
"""
重写equals方法判断两个连接对象是否相同
:param other: 连接对象
:return: Boolean
"""
if isinstance(other, AllSimConnect):
other_ids = other.NobjS.ObjID + other.NobjE.ObjID
return (self.NobjS.ObjID in other_ids
and self.NobjE.ObjID in other_ids)
return False
class SimHost(SimBase):
# todo: 主机类
"""
主机类
"""
def __init__(self, canvas, x, y, id=None, config=None, label=None):
self.ObjID = str(uuid4()) if id is None else id
super().__init__(canvas, x, y, self.ObjID, config, label)
self.ObjType = 1
self.ObjLabel = label if label is not None else self.set_default_name()
self.interface = [{}]
self.connections = [None]
self.set_default_config()
def create_packet(self, ip, mac, message, ping=False):
"""
创建数据包
:param ip: 目的主机ip
:param mac: 目的主机mac
:param message: 消息
:return:
"""
if ping:
packet = SimPacket(self.interface[0]["ip"], self.interface[0]["mac"], ip, mac, message, True)
else:
packet = SimPacket(self.interface[0]["ip"], self.interface[0]["mac"], ip, mac, message)
print(f"创建数据包成功,数据包由{packet.source_ip} 发往 {packet.destination_ip}")
self.send(packet)
def send(self, packet):
"""
发送数据包
:param packet:
:return:
"""
connection: AllSimConnect = self.connections[0]
print(f"数据包从 {self.ObjLabel} 发出")
packet.up_jump = connection
connection.transfer(self, packet)
def receive(self, packet: SimPacket):
"""
接收数据
:param packet: 数据包
:return:
"""
print(f"主机{self.ObjLabel}接受到数据{packet.message}")
if packet.destination_ip == self.interface[0]["ip"]:
if not packet.ping:
self.transfer_animate(True, packet)
else:
self.canvas.receive = self
else:
self.transfer_animate(False, packet)
def __str__(self):
str = ""
config = self.get_config()
for index, data in config.iterrows():
str += f"【接口{data['node_ifs']}\n"
str += f"AppAddr: /Root\n"
str += f"PORT: {data['conn_port']}\n"
str += f"IP: {data['ip']}\n"
str += f"MAC: {data['mac']}\n"
return str
class SimRouter(SimBase):
# todo: 路由类
"""
路由类
"""
def __init__(self, canvas, x, y, id=None, config=None, label=None, *args):
self.ObjID = str(uuid4()) if id is None else id
super().__init__(canvas, x, y, self.ObjID, config, label)
self.ObjType = 2
self.ObjLabel = label if label is not None else self.set_default_name()
self.router_table = {}
self.set_default_router_table()
def set_default_router_table(self):
"""
将数据库中的路由表信息提取
:return:
"""
sql = f"select * from router_table where obj_id='{self.ObjID}'"
router_tables = search(sql)
for index, router_table in router_tables.iterrows():
if router_table["node_ifs"] in self.router_table:
self.router_table[router_table["node_ifs"]].append(router_table["segment"])
else:
self.router_table[router_table["node_ifs"]] = [router_table["segment"]]
def check_destination_ip(self, destination_ip, network):
"""
检查目标ip是否属于网段范围内
:param destination_ip: 目标ip
:param network: 网段
:return:10.2.3.0/24
"""
ip = ipaddress.ip_address(destination_ip)
network = ipaddress.ip_network(network)
if ip in network:
return True
if network == "0.0.0.0/24": # 如果网段为 0.0.0.0/24 则为默认路由
return True
def transmit(self, packet: SimPacket):
"""
转发数据包
:return:
"""
flag = False
next_hop_ifs = None
for conn in self.connections:
if isinstance(conn, AllSimConnect):
if conn.ConfigCorrect == 0:
continue
if conn == packet.up_jump:
continue
ifs = self.connections.index(conn) + 1
if self.router_table.get(ifs) is None:
continue
for network in self.router_table.get(ifs):
if self.check_destination_ip(packet.destination_ip, network):
flag = True
next_hop_ifs = ifs
if flag:
conn = self.connections[next_hop_ifs - 1]
packet.up_jump = conn
conn.transfer(self, packet)
else:
for conn in self.connections:
if isinstance(conn, AllSimConnect):
if conn == packet.up_jump:
continue
if conn.NobjS != self:
if conn.NobjE.ObjType == 1:
conn.transfer(self, packet)
break
error_message = "路由寻址失败"
if packet.ping:
self.canvas.check_error_obj = self
return
self.transfer_animate(False, packet, error_message)
def receive(self, packet):
"""
接收数据
:param packet: 数据包
:return:
"""
print(f"{self.ObjLabel}-路由器接受到数据{packet.message}")
self.transmit(packet)
def add_config(self, router, router_ifs):
sql = f"insert into router_table values ('{self.ObjID}', {router_ifs}, '{router}')"
execute_sql(sql)
def delete_config(self, ifs, network):
sql = f"delete from router_table where obj_id='{self.ObjID}' and node_ifs={ifs} and segment='{network}'"
execute_sql(sql)
def get_table_config(self):
"""
返回对象的路由表配置信息,用于展示
:return:
"""
str = ""
sql = f"select * from router_table where obj_id='{self.ObjID}'"
router_tables = search(sql)
for index, router in router_tables.iterrows():
str += f"网段号: {router['segment']}\n"
str += f"接口号: {router['node_ifs']}\n"
return str
class SimSwitch(SimBase):
# todo: 交换机类
"""
交换机类
"""
def __init__(self, canvas, x, y, id=None, config=None, label=None, *args):
self.ObjID = str(uuid4()) if id is None else id
super().__init__(canvas, x, y, self.ObjID, config, label)
self.ObjType = 3
self.ObjLabel = label if label is not None else self.set_default_name()
self.mac_table = {}
self.set_default_mac_table()
def set_default_mac_table(self):
"""
将数据库中的路由表信息提取
:return:
"""
sql = f"select * from mac_table where obj_id='{self.ObjID}'"
router_tables = search(sql)
for index, router_table in router_tables.iterrows():
if router_table["node_ifs"] in self.mac_table:
self.mac_table[router_table["node_ifs"]].append(router_table["mac"])
else:
self.mac_table[router_table["node_ifs"]] = [router_table["mac"]]
def add_config(self, router, router_ifs):
sql = f"insert into mac_table values ('{self.ObjID}', {router_ifs}, '{router}')"
execute_sql(sql)
def delete_config(self, ifs, mac):
sql = f"delete from mac_table where obj_id='{self.ObjID}' and node_ifs={ifs} and mac='{mac}'"
execute_sql(sql)
def get_table_config(self):
"""
返回对象的交换表配置信息,用于展示
:return:
"""
str = ""
sql = f"select * from mac_table where obj_id='{self.ObjID}'"
router_tables = search(sql)
for index, router in router_tables.iterrows():
str += f"网段号: {router['mac']}\n"
str += f"接口号: {router['node_ifs']}\n"
return str
def transmit(self, packet: SimPacket):
"""
转发数据包
:return:
"""
flag = False
next_hub_ifs = None
for conn in self.connections:
if isinstance(conn, AllSimConnect):
if conn.ConfigCorrect == 0:
continue
ifs = self.connections.index(conn) + 1
if packet.destination_mac in self.mac_table.get(ifs, []):
flag = True
next_hub_ifs = ifs
if flag:
conn = self.connections[next_hub_ifs - 1]
packet.up_jump = conn
conn.transfer(self, packet)
return
for conn in self.connections: # 将数据包往所有接口进行转发
if isinstance(conn, AllSimConnect):
if conn == packet.up_jump:
continue
if conn.ConfigCorrect == 0:
continue
new_packet = SimPacket(packet.source_ip,
packet.source_mac,
packet.destination_ip,
packet.destination_mac,
packet.message)
new_packet.up_jump = conn
threading.Thread(target=conn.transfer, args=(self, new_packet)).start()
def receive(self, packet: SimPacket):
"""
接收数据
:param packet: 数据包
:return:
"""
print(f"交换机{self.ObjLabel}接受到数据{packet.message}")
self.transmit(packet)
class SimHub(SimBase):
"""
集线器类
"""
def __init__(self, canvas, x, y, id=None, config=None, label=None, *args):
self.ObjID = str(uuid4()) if id is None else id
super().__init__(canvas, x, y, self.ObjID, config, label)
self.ObjType = 4
self.ObjLabel = label if label is not None else self.set_default_name()
def transmit(self, packet: SimPacket):
"""
集线器转发数据包
:return:
"""
for conn in self.connections: # 将数据包往所有接口进行转发
if isinstance(conn, AllSimConnect):
if conn == packet.up_jump:
continue
if conn.ConfigCorrect == 0:
continue
new_packet = SimPacket(packet.source_ip,
packet.source_mac,
packet.destination_ip,
packet.destination_mac,
packet.message)
new_packet.up_jump = conn
threading.Thread(target=conn.transfer, args=(self, new_packet)).start()
def receive(self, packet: SimPacket):
"""
接收数据
:param packet: 数据包
:return:
"""
print(f"集线器-{self.ObjLabel}接受到数据,将进行转发!")
self.transmit(packet)

@ -0,0 +1,332 @@
import ipaddress
import re
import sqlite3
from time import sleep
from tkinter import messagebox
import ttkbootstrap as tk
from ttkbootstrap import *
from ttkbootstrap import ttk
import pandas as pd
import sys
from PIL import Image, ImageTk
from SimObjs import SimRouter
def round_rectangle(cv, x1, y1, x2, y2, radius=30, **kwargs):
"""
绘制圆角矩形
:param cv: canvas对象
:param radius: 圆角值
:return:
"""
points = [x1 + radius, y1,
x1 + radius, y1,
x2 - radius, y1,
x2 - radius, y1,
x2, y1,
x2, y1 + radius,
x2, y1 + radius,
x2, y2 - radius,
x2, y2 - radius,
x2, y2,
x2 - radius, y2,
x2 - radius, y2,
x1 + radius, y2,
x1 + radius, y2,
x1, y2,
x1, y2 - radius,
x1, y2 - radius,
x1, y1 + radius,
x1, y1 + radius,
x1, y1]
return cv.create_polygon(points, **kwargs, smooth=True)
def validate_ip_address(ip_address):
"""
匹配ip地址格式是否规范
:param ip_address: IP地址
:return: Boolean
"""
# 定义IP地址的正则表达式模式
pattern_with_subnet = r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})$'
pattern_without_subnet = r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$'
# 使用re模块进行匹配
match_with_subnet = re.match(pattern_with_subnet, ip_address)
match_without_subnet = re.match(pattern_without_subnet, ip_address)
if match_with_subnet:
# 带有子网掩码的IP地址
# 检查每个组件的取值范围是否在 0-255 之间
for group in match_with_subnet.groups()[:4]:
if not (0 <= int(group) <= 255):
return False
# 检查子网掩码的取值范围是否在 0-32 之间
subnet_mask = int(match_with_subnet.groups()[4])
if not (0 <= subnet_mask <= 32):
return False
return True
elif match_without_subnet:
# 不带子网掩码的IP地址
# 检查每个组件的取值范围是否在 0-255 之间
for group in match_without_subnet.groups():
if not (0 <= int(group) <= 255):
return False
return True
else:
# IP地址格式不正确
return False
class ExportUtil():
def __init__(self, path):
self.conn = sqlite3.connect('./network.db')
self.path = path
def get_table_names(self):
cursor = self.conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") # 如果你使用SQLite数据库
tables = cursor.fetchall()
cursor.close()
return [table[0] for table in tables]
def export(self):
tables = self.get_table_names()
with pd.ExcelWriter(self.path, engine='openpyxl') as writer:
for table in tables:
table_name = table
# a. 从数据库中获取表的数据并存储在DataFrame中
query = f"SELECT * FROM {table_name}"
df = pd.read_sql(query, self.conn)
# b. 使用Pandas将数据写入Excel文件的不同sheet中
df.to_excel(writer, sheet_name=table_name, index=False)
def import_data(self):
excel_file = pd.ExcelFile(self.path)
sheet_names = excel_file.sheet_names
print(sheet_names)
cursor = self.conn.cursor()
for sheet_name in sheet_names:
# 4. 使用 Pandas 读取工作表数据
df = pd.read_excel(excel_file, sheet_name=sheet_name)
# 5. 获取工作表的列名
columns = df.columns.tolist()
# 6. 构造插入语句
columns_str = ', '.join(columns)
placeholders = ', '.join(['?' for _ in range(len(columns))])
sql = f"INSERT INTO {sheet_name} ({columns_str}) VALUES ({placeholders})"
# 7. 将数据插入数据库
for index, row in df.iterrows():
# 8. 使用动态生成的 SQL 语句将数据插入数据库
cursor.execute(sql, tuple(row))
self.conn.commit()
class RouterConfigWindow(tk.Toplevel):
def __init__(self, parent, router_obj):
super().__init__(parent)
self.geometry("435x433+350+200")
self.title(f"{router_obj.ObjLabel}路由表配置")
self.router_obj = router_obj
self.interface_entries = []
self.router_table = {}
self.create_interface_inputs()
self.create_router_table()
def create_interface_inputs(self):
label_text = ["接口1", "接口2", "接口3", "接口4"]
for i in range(4):
label = tk.Label(self, text=label_text[i], font=("黑体", 16))
label.grid(row=i, column=0, padx=10, pady=5, sticky="w")
entry = tk.Entry(self, width=20, font=("黑体", 16),)
entry.grid(row=i, column=1, padx=10, pady=5, sticky="w")
self.interface_entries.append(entry)
button = tk.Button(self, text="添加", font=("黑体", 16), command=lambda index=i: self.add_router_entry(index))
button.grid(row=i, column=2, padx=10, pady=5)
lab = LabelFrame(self, text="示例")
lab.grid(row=4, column=0, columnspan=3, sticky=W, padx=20)
Label(lab, text="10.1.2.0/24 或者 10.1.2.12" if self.router_obj.ObjType == 2 else "MAC11", font=("黑体", 16)).pack()
def create_router_table(self):
def on_right_click(event):
row = self.router_treeview.identify_row(event.y) # 获取鼠标位置的行索引
if row:
self.router_treeview.selection_set(row) # 选中该行
delete_menu.post(event.x_root, event.y_root) # 在鼠标位置弹出删除菜单
def delete_row():
selected_items = self.router_treeview.selection() # 获取选中的行
for item in selected_items:
ifs, network = int(self.router_treeview.item(item)["values"][0][-1:]), self.router_treeview.item(item)["values"][1]
self.router_obj.delete_config(ifs, network)
self.router_treeview.delete(item)
self.router_table_frame = tk.Frame(self)
self.router_table_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
style = ttk.Style()
style.configure("Custom.Treeview.Heading", font=("宋体", 15))
style.configure("Custom.Treeview", rowheight=30, font=("宋体", 15))
self.router_treeview = ttk.Treeview(self.router_table_frame, style="Custom.Treeview", columns=("Interface", "Route"), show="headings")
self.router_treeview.heading("Interface", text="接口")
self.router_treeview.heading("Route", text="网段")
self.router_treeview.pack(side="left", fill="both")
scrollbar = ttk.Scrollbar(self.router_table_frame, orient="vertical", command=self.router_treeview.yview)
scrollbar.pack(side="right", fill="y")
self.router_treeview.configure(yscrollcommand=scrollbar.set)
self.router_table = self.router_obj.router_table
self.router_treeview.bind("<Button-3>", on_right_click)
# 创建删除菜单
delete_menu = tk.Menu(self.master, tearoff=False)
delete_menu.add_command(label="删除", command=delete_row)
self.update_router_table()
def add_router_entry(self, index):
entry_text = self.interface_entries[index].get()
try:
ipaddress.ip_network(entry_text)
if isinstance(self.router_obj, SimRouter):
if not validate_ip_address(entry_text):
messagebox.showerror("注意", message="添加的网段信息格式不合格")
self.interface_entries[index].delete(0, tk.END)
self.focus_set()
return
if entry_text:
if index + 1 in self.router_table:
self.router_table[index + 1].append(entry_text)
else:
self.router_table[index + 1] = [entry_text]
self.interface_entries[index].delete(0, tk.END)
self.router_obj.add_config(entry_text, index + 1)
self.update_router_table()
self.master.message.show_message(f"{self.router_obj.ObjLabel}添加配置{entry_text}成功!")
except:
messagebox.showerror("注意", message="网段格式错误!网段示例如下:\n10.1.2.0/24\n10.1.2.12")
return
def update_router_table(self):
self.router_treeview.delete(*self.router_treeview.get_children())
for i, entrys in self.router_table.items():
for entry in entrys:
self.router_treeview.insert("", "end", values=(f"接口{i}", entry))
class SwitchConfigWindow(RouterConfigWindow):
def __init__(self, parent, router_obj):
super().__init__(parent, router_obj)
self.geometry("435x433+350+200")
self.title(f"{router_obj.ObjLabel}交换表配置")
self.router_obj = router_obj
self.interface_entries = []
self.router_table = {}
self.create_interface_inputs()
self.create_router_table()
def create_router_table(self):
def on_right_click(event):
row = self.router_treeview.identify_row(event.y) # 获取鼠标位置的行索引
if row:
self.router_treeview.selection_set(row) # 选中该行
delete_menu.post(event.x_root, event.y_root) # 在鼠标位置弹出删除菜单
def delete_row():
selected_items = self.router_treeview.selection() # 获取选中的行
for item in selected_items:
ifs, network = int(self.router_treeview.item(item)["values"][0][-1:]), self.router_treeview.item(item)["values"][1]
self.router_obj.delete_config(ifs, network)
self.router_treeview.delete(item)
self.router_table_frame = tk.Frame(self)
self.router_table_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
self.router_treeview = ttk.Treeview(self.router_table_frame, columns=("Interface", "Route"), show="headings")
self.router_treeview.heading("Interface", text="接口")
self.router_treeview.heading("Route", text="mac")
self.router_treeview.pack(side="left", fill="both")
scrollbar = ttk.Scrollbar(self.router_table_frame, orient="vertical", command=self.router_treeview.yview)
scrollbar.pack(side="right", fill="y")
self.router_treeview.configure(yscrollcommand=scrollbar.set)
self.router_table = self.router_obj.mac_table
self.router_treeview.bind("<Button-3>", on_right_click)
# 创建删除菜单
delete_menu = tk.Menu(self.master, tearoff=False)
delete_menu.add_command(label="删除", command=delete_row)
self.update_router_table()
def add_router_entry(self, index):
entry_text = self.interface_entries[index].get()
if isinstance(self.router_obj, SimRouter):
if not validate_ip_address(entry_text):
messagebox.showerror("注意", message="添加的网段信息格式不合格")
self.interface_entries[index].delete(0, tk.END)
self.focus_set()
return
if entry_text:
if index + 1 in self.router_table:
self.router_table[index + 1].append(entry_text)
else:
self.router_table[index + 1] = [entry_text]
self.interface_entries[index].delete(0, tk.END)
self.router_obj.add_config(entry_text, index + 1)
self.master.message.show_message(f"{self.router_obj.ObjLabel}添加配置{entry_text}成功!")
self.update_router_table()
class TransferAnimate:
"""
校验动画
"""
def __init__(self, master, flag=False):
self.master = master
self.flag = flag
self.width, self.height = 320, 140
self.host_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机@2x.png").resize((40, 40)))
self.filename = ImageTk.PhotoImage(Image.open("../datas/images/背景@2x.png").resize((self.width, self.height)))
self.toplevel = Toplevel(alpha=0.9)
self.toplevel.geometry("{}x{}+200+150".format(self.width, self.height))
self.toplevel.title("校验")
self.toplevel.resizable(width=False, height=False)
self.canvas = Canvas(self.toplevel, width=self.width, height=self.height, bg="red")
self.canvas.place(x=0, y=0, anchor=NW)
back = self.canvas.create_image(10, 20, image=master.check_filename)
self.send_x, self.receive_x, self.obj_y = 50, self.width - 50, self.height / 2 - 20
self.canvas.create_image(self.send_x, self.obj_y, image=master.host_img)
self.canvas.create_image(self.receive_x, self.obj_y, image=master.host_img)
line = self.canvas.create_line(self.send_x, self.obj_y, self.receive_x, self.obj_y, width=2, fill="#c372f0")
self.canvas.tag_lower(line)
self.canvas.tag_lower(back)
self.animate()
def animate(self):
for i in range(3):
self.canvas.create_image(self.send_x, self.obj_y, image=self.master.pack_img, tags="check_img")
self.move(self.canvas, self.receive_x, self.obj_y, 500)
self.canvas.delete("check_img")
self.canvas.update()
self.canvas.create_image(self.receive_x - self.send_x - 45, self.obj_y, image=self.master.true_img if self.flag else self.master.false_img)
self.canvas.update()
sleep(2)
if not self.flag:
messagebox.showerror("提示", "校验失败,请检查组件{}的相关配置!".format(self.master.check_error_obj.ObjLabel))
self.toplevel.destroy()
def move(self, cv, target_x, target_y, duration):
start_x, start_y = cv.coords("check_img")
distance_x = target_x - start_x
distance_y = target_y - start_y
steps = duration // 10 # 以10毫秒为间隔进行移动
step_x = distance_x / steps
step_y = distance_y / steps
self._move_step(cv, start_x, start_y, target_x, target_y, step_x, step_y, steps)
def _move_step(self, cv, start_x, start_y, target_x, target_y, step_x, step_y, steps):
if steps > 0:
new_x = start_x + step_x
new_y = start_y + step_y
cv.coords("check_img", new_x, new_y)
cv.update() # 更新画布显示
sleep(0.01) # 添加延迟以控制动画速度
self._move_step(cv, new_x, new_y, target_x, target_y, step_x, step_y, steps - 1)
else:
cv.coords("check_img", target_x, target_y)
cv.delete("check_img")

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

@ -0,0 +1,19 @@
,组件名称,接口,ip,mac,端口,应用层地址
0,SHO3,1,10.1.1.10,MAC1,80.0,10.1.2.10:10810:Name3
1,SRO1,1,10.1.1.10,MAC11,,
2,SRO1,2,,,,
3,SRO2,1,,,,
4,SRO2,2,10.1.1.12,MAC13,,
5,SRO3,1,10.1.12.10,MAC31,,
6,SRO2,3,10.1.1.13,MAC14,,
7,SRO4,1,10.1.2.11,MAC21,,
8,SRO5,1,10.1.13.10,MAC41,,
9,SRO3,2,10.1.12.11,MAC32,,
10,SHO4,1,10.1.2.15,MAC3,80.0,10.1.2.10:10810:Name3
11,SRO4,2,10.1.2.12,MAC22,,
12,SRO5,2,10.1.13.11,MAC42,,
13,SHO2,1,10.1.12.15,MAC5,80.0,10.1.2.10:10810:Name3
14,SRO3,3,10.1.12.12,MAC33,,
15,SHO1,1,10.1.20.5,MAC4,80.0,10.1.20.5:10810:Name3
16,SHO5,1,10.1.22.11,MAC2,80.0,10.1.2.10:10810:Name3
17,SRO3,4,10.1.12.13,MAC34,,
1 组件名称 接口 ip mac 端口 应用层地址
2 0 SHO3 1 10.1.1.10 MAC1 80.0 10.1.2.10:10810:Name3
3 1 SRO1 1 10.1.1.10 MAC11
4 2 SRO1 2
5 3 SRO2 1
6 4 SRO2 2 10.1.1.12 MAC13
7 5 SRO3 1 10.1.12.10 MAC31
8 6 SRO2 3 10.1.1.13 MAC14
9 7 SRO4 1 10.1.2.11 MAC21
10 8 SRO5 1 10.1.13.10 MAC41
11 9 SRO3 2 10.1.12.11 MAC32
12 10 SHO4 1 10.1.2.15 MAC3 80.0 10.1.2.10:10810:Name3
13 11 SRO4 2 10.1.2.12 MAC22
14 12 SRO5 2 10.1.13.11 MAC42
15 13 SHO2 1 10.1.12.15 MAC5 80.0 10.1.2.10:10810:Name3
16 14 SRO3 3 10.1.12.12 MAC33
17 15 SHO1 1 10.1.20.5 MAC4 80.0 10.1.20.5:10810:Name3
18 16 SHO5 1 10.1.22.11 MAC2 80.0 10.1.2.10:10810:Name3
19 17 SRO3 4 10.1.12.13 MAC34

Binary file not shown.

Binary file not shown.

@ -0,0 +1,104 @@
import sqlite3
import sys
import pandas as pd
from pandas import DataFrame
conn = sqlite3.connect(sys.path[0]+"/network.db")
def execute_sql(sql):
"""
执行sql语句
:param sql:
:return:
"""
cursor = conn.cursor()
cursor.execute(sql)
conn.commit()
def search(sql) -> DataFrame:
return pd.read_sql(sql, conn)
def delete_obj(obj_id):
cursor = conn.cursor()
delete_obj_sql = f"delete from sim_objs where ObjID='{obj_id}'"
cursor.execute(delete_obj_sql)
delete_conn_sql = f"delete from sim_conn where conn_id in (select conn_id from conn_config where node_id='{obj_id}')"
cursor.execute(delete_conn_sql)
conn.commit()
def truncate_db():
init_database()
def init_database():
cursor = conn.cursor()
cursor.execute("""
DROP TABLE IF EXISTS `conn_config`;
""")
cursor.execute("""
CREATE TABLE `conn_config` (
`conn_id` varchar(55) NULL DEFAULT NULL,
`node_id` varchar(55) NULL DEFAULT NULL,
`node_ifs` int(0) NULL DEFAULT NULL,
`ip` varchar(55) NULL DEFAULT NULL,
`mac` varchar(128) NULL DEFAULT NULL,
`conn_port` varchar(32) NULL DEFAULT NULL,
`addr` varchar(255) NULL DEFAULT NULL,
CONSTRAINT `conn_config_sim_conn_conn_id_fk` FOREIGN KEY (`conn_id`) REFERENCES `sim_conn` (`conn_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ;
""")
cursor.execute("""
DROP TABLE IF EXISTS `mac_table`;
""")
cursor.execute("""
CREATE TABLE `mac_table` (
`obj_id` varchar(55) NULL DEFAULT NULL,
`node_ifs` int(0) NULL DEFAULT NULL,
`mac` varchar(55) NULL DEFAULT NULL,
CONSTRAINT `mac_table_sim_objs_ObjID_fk` FOREIGN KEY (`obj_id`) REFERENCES `sim_objs` (`ObjID`) ON DELETE CASCADE ON UPDATE CASCADE
) ;
""")
cursor.execute("""
DROP TABLE IF EXISTS `router_table`;
""")
cursor.execute("""
CREATE TABLE `router_table` (
`obj_id` varchar(55) NULL DEFAULT NULL,
`node_ifs` int(0) NULL DEFAULT NULL,
`segment` varchar(55) NULL DEFAULT NULL,
CONSTRAINT `router_table_sim_objs_ObjID_fk` FOREIGN KEY (`obj_id`) REFERENCES `sim_objs` (`ObjID`) ON DELETE CASCADE ON UPDATE CASCADE
) ;
""")
cursor.execute("""
DROP TABLE IF EXISTS `sim_conn`;
""")
cursor.execute("""
CREATE TABLE `sim_conn` (
`conn_id` varchar(255) NOT NULL ,
`ConfigCorrect` int(0) NULL DEFAULT NULL ,
PRIMARY KEY (`conn_id`)
) ;
""")
cursor.execute("""
DROP TABLE IF EXISTS `sim_objs`;
""")
cursor.execute("""
CREATE TABLE `sim_objs` (
`ObjID` varchar(50) NOT NULL,
`ObjType` int(0) NULL DEFAULT NULL,
`ObjLabel` varchar(20) NULL DEFAULT NULL,
`ObjX` int(0) NULL DEFAULT NULL,
`ObjY` int(0) NULL DEFAULT NULL,
`ConfigCorrect` int(0) NULL DEFAULT NULL,
PRIMARY KEY (`ObjID`)
) ;
""")
conn.commit()
if __name__ == '__main__':
init_database()

@ -0,0 +1,114 @@
import re
from NetworkAnalog.SimObjs import SimBase, AllSimConnect, SimRouter, SimHost
class SimPacket(): # 需要补充至编程13.7当中
def __init__(self, source_ip, source_mac, destination_ip, message=None, ping=False):
"""
:param source_mac: 源主机mac地址
:param source_ip: 源主机ip地址
:param destination_mac: 目的主机mac地址
:param destination_ip: 目的主机ip地址
:param message: 数据
"""
self.source_mac = source_mac
self.source_ip = source_ip
self.destination_ip = destination_ip
self.message = message
self.up_jump = None # 上一跳连接对象
self.ping = ping
self.flag = False # 是否传输成功
class SimHost(SimBase):
def receive(self, packet: SimPacket): # 修改编程13.7中SimHost的receive方法
# 判断目的IP是否与本机IP一致以及判断当前主机是否联网
if packet.destination_ip == self.interface[0]["ip"] and self.network_online:
print(f"主机{self.ObjLabel}接受到数据{packet.message}")
packet.flag = True # 将packet的传输状态改为True视为传输成功
else:
print(f"数据传输失败")
def validate_ip_address(ip_address):# 定义IP地址的正则表达式模式
pattern_with_subnet = r'^(\d{1,3})\.(\d{1,3})\.(' \
r'\d{1,3})\.(\d{1,3})/(\d{1,2})$'
pattern_without_subnet = r'^(\d{1,3})\.(\d{1,3})' \
r'\.(\d{1,3})\.(\d{1,3})$'
match_with_subnet = re.match(pattern_with_subnet,
ip_address) # 使用re模块进行匹配
match_without_subnet = re.match(pattern_without_subnet, ip_address)
if match_with_subnet: # 带有子网掩码的IP地址
# 检查每个组件的取值范围是否在 0-255 之间
for group in match_with_subnet.groups()[:4]:
if not (0 <= int(group) <= 255):
return False
subnet_mask = int(match_with_subnet.groups()[4])
# 检查子网掩码的取值范围是否在 0-32 之间
if not (0 <= subnet_mask <= 32):
return False
return True
elif match_without_subnet: # 不带子网掩码的IP地址
for group in match_without_subnet.groups():
if not (0 <= int(group) <= 255):
return False
return True
else:
return False # IP地址格式不正确
def is_same_subnet(ip1, ip2): # 判断两个IP地址是否属于同一网段
# 将IP地址和子网掩码转换为整数列表
ip1_parts = [int(part) for part in ip1.split('.')]
ip2_parts = [int(part) for part in ip2.split('.')]
subnet_mask_parts = [int(part) for part in "255.255.255.0".split('.')]
# 计算网络地址
network1 = [ip1_parts[i] & subnet_mask_parts[i] for i in range(4)]
network2 = [ip2_parts[i] & subnet_mask_parts[i] for i in range(4)]
# 比较网络地址是否相同
return network1 == network2
class NetworkAnalog():
...
def check_network(self): # 判断各网络节点是否配置正确
flag = True
sim_host_list = []
for key, tag in self.AllSimObjs.items(): # 遍历所有组件
# todo: 判断主机的ip配置是否都合格
if tag.ObjType == 1: # 如果该组件为主机
for interface in tag.interface: # 遍历该主机下所有接口
index = tag.interface.index(interface) + 1 # 获取当前接口号
ip_ = interface["ip"] # 获取当前接口IP
if not validate_ip_address(ip_): # 判断主机配置的IP是否正确
self.message.show_message(f"主机{tag.ObjLabel}的接口{index} IP 配置错误")
flag = False
sim_host_list.append(tag) # 将所有主机组件添加到列表中
# todo: 判断路由器的四个接口是否都在同一网段下
if tag.ObjType == 2: # 如果当前组件为路由器
ip_ = tag.interface[0]["ip"] # 将第一个接口设为默认
for interface in tag.interface: # 遍历所有接口
index = tag.interface.index(interface) + 1 # 获取当前接口号
if not is_same_subnet(ip_, interface["ip"]): # 判断所有接口是否在同一网段下
self.message.show_message(f"路由器{tag.ObjLabel}中接口{index}不在同一网段下")
flag = False
# todo: 检查路由表是否能跳转到下一跳
if tag.ObjType == 2: # 如果当前组件为路由器
for conn in tag.connections: # 遍历该组件所有链接线
next_jump = conn.NobjE # 获取下一跳组件
if not is_same_subnet(tag.interface[conn.IfsS]["ip"], next_jump.interface[conn.IfsE]["ip"]): # 检查路由表是否能跳转到下一跳
self.message.show_message(f"路由器组件{tag.ObjLabel}路由表配置错误,请检查")
flag = False
# todo: 判断从所有主机发送数据包到其他所有主机能否成功
for sim_host in sim_host_list: # 遍历所有主机组件
sim_host: SimHost = sim_host
for destination_sim_host in sim_host_list: # 遍历所有主机组件
packet = SimPacket(sim_host.interface[0]['ip'],
sim_host.interface[0]['mac'],
destination_sim_host.interface[0]["ip"]) # 封装数据包,将发送主机信息和接收主机信息封装到数据包中
sim_host.send(packet) # 模拟发送
if not packet.flag: # 判断是否传输成功
self.message.show_message(f"主机{sim_host.ObjLabel}传输至{destination_sim_host.ObjLabel}失败,请检查配置!")
return flag

Binary file not shown.

@ -0,0 +1,19 @@
import socket
def is_same_subnet(ip1, ip2):
# 将IP地址和子网掩码转换为整数列表
ip1_parts = [int(part) for part in ip1.split('.')]
ip2_parts = [int(part) for part in ip2.split('.')]
subnet_mask_parts = [int(part) for part in "255.255.255.0".split('.')]
# 计算网络地址
network1 = [ip1_parts[i] & subnet_mask_parts[i] for i in range(4)]
network2 = [ip2_parts[i] & subnet_mask_parts[i] for i in range(4)]
# 比较网络地址是否相同
return network1 == network2
print(is_same_subnet("192.168.10.23", "192.12.10.21"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="34px" height="40px" viewBox="0 0 34 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>主机</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#0055D7" offset="0%"></stop>
<stop stop-color="#4BC1FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-2">
<stop stop-color="#0042BE" offset="0%"></stop>
<stop stop-color="#0073FC" offset="100%"></stop>
</linearGradient>
<linearGradient x1="34.9365234%" y1="39.183214%" x2="50%" y2="70.6841363%" id="linearGradient-3">
<stop stop-color="#0054D5" offset="0%"></stop>
<stop stop-color="#2A92EE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="78.125%" y1="66.0866477%" x2="21.875%" y2="27.2061435%" id="linearGradient-4">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="77.6337595%" id="linearGradient-5">
<stop stop-color="#0080E3" offset="0%"></stop>
<stop stop-color="#0072C4" offset="100%"></stop>
</linearGradient>
<linearGradient x1="88.7402344%" y1="46.21875%" x2="21.1230469%" y2="53.78125%" id="linearGradient-6">
<stop stop-color="#8FC4FE" offset="0%"></stop>
<stop stop-color="#1896F6" offset="100%"></stop>
</linearGradient>
<linearGradient x1="13.234747%" y1="63.3167614%" x2="100%" y2="63.3167614%" id="linearGradient-7">
<stop stop-color="#7E8CAA" offset="0%"></stop>
<stop stop-color="#C7CDD9" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50.6091477%" y1="44.7228065%" x2="48.1508876%" y2="50%" id="linearGradient-8">
<stop stop-color="#6B7997" offset="0%"></stop>
<stop stop-color="#4B4E55" offset="100%"></stop>
</linearGradient>
</defs>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="4网络构建与联通V2.0" transform="translate(-268.000000, -696.000000)">
<g id="主机" transform="translate(268.000000, 696.000000)">
<polygon id="路径-81" fill="url(#linearGradient-1)" points="23.8461538 30 23.8461538 31.5384615 30.7692308 33.8461538 16.9230769 40 6.15384615 35.3846154 10 33.8461538 18.4615385 30 23.8461538 27.6923077"></polygon>
<polygon id="路径-82" fill="url(#linearGradient-2)" points="16.9230769 40 16.9230769 35.3846154 16.9230769 30 6.15384615 35.3846154"></polygon>
<polygon id="路径-88" fill="url(#linearGradient-3)" points="26.1538462 32.3076923 16.9230769 35.3846154 16.9230769 30 23.8461538 27.6923077 23.8461538 31.5384615"></polygon>
<polygon id="路径-77" fill="url(#linearGradient-4)" points="11.5384615 33.8461538 8.46153846 8.46153846 30.7692308 0 33.8461538 24.6153846"></polygon>
<polygon id="路径-78" fill="url(#linearGradient-5)" points="11.5384615 33.8461538 1.53846154 27.6923077 0 8.46153846 8.46153846 8.46153846"></polygon>
<polygon id="路径-79" fill="url(#linearGradient-6)" points="30.7692308 0 20.7692308 0.769230769 0 8.46153846 8.46153846 8.46153846"></polygon>
<polygon id="路径-80" fill="url(#linearGradient-7)" points="11.5384615 10 29.2307692 3.84615385 31.5384615 22.3076923 13.8461538 30"></polygon>
<polygon id="路径-83" fill="url(#linearGradient-8)" points="11.5384615 10 13.0769231 10 15.3846154 29.2307692 13.8461538 30"></polygon>
<line x1="29.2307692" y1="3.84615385" x2="31.5384615" y2="22.3076923" id="路径-85" stroke="#0056D7" stroke-width="0.769230769"></line>
<line x1="29.2307692" y1="3.84615385" x2="11.5384615" y2="10" id="路径-86" stroke="#2DA2E9" stroke-width="0.769230769"></line>
<line x1="31.5384615" y1="22.3076923" x2="13.8461538" y2="30" id="路径-86" stroke="#92D6FF" stroke-width="0.769230769"></line>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -0,0 +1,391 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="54px" height="23px" viewBox="0 0 54 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>交换机</title>
<defs>
<linearGradient x1="13.6935089%" y1="47.3733367%" x2="98.4463875%" y2="51.0994595%" id="linearGradient-1">
<stop stop-color="#8FC4FE" offset="0%"></stop>
<stop stop-color="#1896F6" offset="100%"></stop>
</linearGradient>
<linearGradient x1="8.49955214%" y1="56.2692825%" x2="100%" y2="43.7307175%" id="linearGradient-2">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="77.6337595%" id="linearGradient-3">
<stop stop-color="#0080E3" offset="0%"></stop>
<stop stop-color="#0072C4" offset="100%"></stop>
</linearGradient>
<filter x="-86.1%" y="-83.3%" width="272.1%" height="266.7%" filterUnits="objectBoundingBox" id="filter-4">
<feGaussianBlur stdDeviation="0.327635328" in="SourceGraphic"></feGaussianBlur>
</filter>
<filter x="-86.1%" y="-83.3%" width="272.1%" height="266.7%" filterUnits="objectBoundingBox" id="filter-5">
<feGaussianBlur stdDeviation="0.327635328" in="SourceGraphic"></feGaussianBlur>
</filter>
<polygon id="path-6" points="0.640744615 0.660701538 1.65175385 0.660701538 1.65175385 2.07608615 0.640744615 2.07608615"></polygon>
<polygon id="path-8" points="0.615267692 0.670326154 1.65175385 0.670326154 1.65175385 2.08571077 0.615267692 2.08571077"></polygon>
<polygon id="path-10" points="0.577193846 0.680092308 1.65175385 0.680092308 1.65175385 2.09547692 0.577193846 2.09547692"></polygon>
<polygon id="path-12" points="0.532609231 0.691132308 1.65175385 0.691132308 1.65175385 2.10651692 0.532609231 2.10651692"></polygon>
<polygon id="path-14" points="0.472030769 0.701464615 1.65175385 0.701464615 1.65175385 2.11684923 0.472030769 2.11684923"></polygon>
<polygon id="path-16" points="0.410461538 0.00297230769 1.65175385 0.00297230769 1.65175385 1.41835692 0.410461538 1.41835692"></polygon>
<polygon id="path-18" points="0.0428861538 0.0795446154 1.45827077 0.0795446154 1.45827077 1.41538462 0.0428861538 1.41538462"></polygon>
<polygon id="path-20" points="0.619938462 0.0837907692 2.03532308 0.0837907692 2.03532308 1.41538462 0.619938462 1.41538462"></polygon>
<polygon id="path-22" points="0.478258462 0.0837907692 1.89364308 0.0837907692 1.89364308 1.41538462 0.478258462 1.41538462"></polygon>
<polygon id="path-24" points="0.402535385 0.0782707692 1.81792 0.0782707692 1.81792 1.41538462 0.402535385 1.41538462"></polygon>
<polygon id="path-26" points="0.351156923 0.0733169231 1.76654154 0.0733169231 1.76654154 1.41538462 0.351156923 1.41538462"></polygon>
<polygon id="path-28" points="0.29256 0.06992 1.70794462 0.06992 1.70794462 1.41538462 0.29256 1.41538462"></polygon>
<polygon id="path-30" points="0.246843077 0.0622769231 1.66222769 0.0622769231 1.66222769 1.41538462 0.246843077 1.41538462"></polygon>
<polygon id="path-32" points="0.201550769 0.0561907692 1.61693538 0.0561907692 1.61693538 1.41538462 0.201550769 1.41538462"></polygon>
<polygon id="path-34" points="0.156541538 0.0505292308 1.57192615 0.0505292308 1.57192615 1.41538462 0.156541538 1.41538462"></polygon>
<polygon id="path-36" points="0.110966154 0.0394892308 1.52635077 0.0394892308 1.52635077 1.41538462 0.110966154 1.41538462"></polygon>
<polygon id="path-38" points="0.0660984615 0.0326953846 1.48148308 0.0326953846 1.48148308 1.41538462 0.0660984615 1.41538462"></polygon>
<polygon id="path-40" points="0.0203815385 0.0209476923 1.43576615 0.0209476923 1.43576615 1.41538462 0.0203815385 1.41538462"></polygon>
<polygon id="path-42" points="0.683913846 0.0133046154 2.09929846 0.0133046154 2.09929846 1.41538462 0.683913846 1.41538462"></polygon>
</defs>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="4网络构建与联通V2.0" transform="translate(-93.000000, -705.000000)">
<g id="交换机" transform="translate(120.000000, 716.500000) scale(-1, 1) translate(-120.000000, -716.500000) translate(93.000000, 705.000000)">
<g id="编组-11">
<polygon id="路径-58" fill="url(#linearGradient-1)" points="13.4190069 12.2371795 53.3905169 8.84615385 35.3752544 0 0 2.35897436"></polygon>
<polygon id="路径-59" fill="url(#linearGradient-2)" points="53.3905169 8.84615385 53.3905169 18.8717949 13.4190069 23 13.4190069 12.2371795"></polygon>
<polygon id="路径-60" fill="url(#linearGradient-3)" points="0 2.35897436 13.4190069 12.2371795 13.4190069 23 0 12.6794872"></polygon>
<path d="M25.5947804,19.3515137 L25.0201833,19.3716737 L24.9201833,19.3786737 L24.9811833,19.3736737 L24.6525948,19.3860849 L24.6525948,19.170015 L24.8239013,19.1786578 L24.8239013,19.0317303 L25.1661833,19.0196737 L25.1665142,17.3463855 L23.4534495,17.4953992 L23.4531833,19.1276737 L23.7960625,19.1008727 L23.7960625,19.2478002 L23.9673689,19.2391574 L23.9673689,19.4552272 L23.0251833,19.507084 L23.0251833,17.1735296 L25.5947804,17.0006737 L25.5947804,19.3515137 Z" id="形状结合" fill="#FFFFFF" transform="translate(24.309982, 18.253879) rotate(-2.000000) translate(-24.309982, -18.253879) "></path>
<path d="M22.0258956,19.7938214 L21.4512985,19.8139814 L21.3512985,19.8209814 L21.4122985,19.8159814 L21.08371,19.8283926 L21.08371,19.6123227 L21.2550165,19.6209655 L21.2550165,19.474038 L21.5972985,19.4619814 L21.5976294,17.7886932 L19.8845647,17.9377069 L19.8842985,19.5699814 L20.2271776,19.5431804 L20.2271776,19.6901079 L20.3984841,19.6814651 L20.3984841,19.8975349 L19.4562985,19.9493917 L19.4562985,17.6158373 L22.0258956,17.4429814 L22.0258956,19.7938214 Z" id="形状结合" fill="#FFFFFF" transform="translate(20.741097, 18.696187) rotate(-2.000000) translate(-20.741097, -18.696187) "></path>
<g id="编组-8" transform="translate(33.355051, 16.388638) rotate(-2.000000) translate(-33.355051, -16.388638) translate(27.855051, 12.888638)">
<polygon id="矩形" stroke="#FFFFFF" stroke-width="0.5" points="0 0.810897436 10.4687288 0 10.4687288 5.67628205 0 6.48717949"></polygon>
<polygon id="矩形" fill="#FFFFFF" points="0 3.37873932 10.4687288 2.56784188 10.4687288 3.24358974 0 4.05448718"></polygon>
<line x1="2.6171822" y1="0.540598291" x2="2.6171822" y2="6.35202991" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="5.2343644" y1="0.405448718" x2="5.2343644" y2="6.21688034" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="7.98240571" y1="0.135149573" x2="7.98240571" y2="5.9465812" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
</g>
<g id="编组-8" transform="translate(45.701249, 15.072345) rotate(-2.000000) translate(-45.701249, -15.072345) translate(40.201249, 11.572345)">
<polygon id="矩形" stroke="#FFFFFF" stroke-width="0.5" points="0 0.810897436 10.4687288 0 10.4687288 5.67628205 0 6.48717949"></polygon>
<polygon id="矩形" fill="#FFFFFF" points="0 3.37873932 10.4687288 2.56784188 10.4687288 3.24358974 0 4.05448718"></polygon>
<line x1="2.6171822" y1="0.540598291" x2="2.6171822" y2="6.35202991" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="5.2343644" y1="0.405448718" x2="5.2343644" y2="6.21688034" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="7.98240571" y1="0.135149573" x2="7.98240571" y2="5.9465812" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
</g>
<g id="编组-9" transform="translate(16.131359, 14.006410)" fill="#18D6FF">
<ellipse id="椭圆形" filter="url(#filter-4)" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
<ellipse id="椭圆形" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
</g>
<g id="编组-9" transform="translate(16.131359, 16.365385)" fill="#18D6FF">
<ellipse id="椭圆形" filter="url(#filter-5)" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
<ellipse id="椭圆形" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
</g>
<g id="编组-10" transform="translate(1.998575, 5.750000)" fill="#0A609F" stroke="#0865A7" stroke-width="0.5">
<line x1="0" y1="0" x2="9.42185592" y2="6.78205128" id="路径-62"></line>
<line x1="0" y1="1.62179487" x2="9.42185592" y2="8.40384615" id="路径-62"></line>
<line x1="0" y1="3.39102564" x2="9.42185592" y2="10.1730769" id="路径-62"></line>
<line x1="0" y1="5.16025641" x2="9.42185592" y2="11.9423077" id="路径-62"></line>
<line x1="0" y1="6.92948718" x2="9.42185592" y2="13.7115385" id="路径-62"></line>
</g>
<polygon id="矩形" stroke="#0865A7" stroke-width="0.5" fill="#0A609F" points="12.2769638 15.1858974 12.8479853 15.9230769 12.8479853 18.4294872 12.2769638 17.6923077"></polygon>
<polygon id="矩形" stroke="#0865A7" stroke-width="0.5" fill="#0A609F" points="0.428266178 6.78205128 0.999287749 7.51923077 0.999287749 10.025641 0.428266178 9.28846154"></polygon>
</g>
<g id="编组" transform="translate(17.692308, 2.653846)">
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-7" fill="white">
<use xlink:href="#path-6"></use>
</mask>
<g id="Clip-45"></g>
<polygon id="Fill-44" fill="#0F819B" mask="url(#mask-7)" points="1.15806769 1.99116308 1.51332923 0.755532308 1.53880615 0.745624615 1.19486769 1.98267077"></polygon>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-9" fill="white">
<use xlink:href="#path-8"></use>
</mask>
<g id="Clip-49"></g>
<polygon id="Fill-48" fill="#0F859F" mask="url(#mask-9)" points="1.13188308 2.00078769 1.47440615 0.765156923 1.51403692 0.755249231 1.15877538 1.99088"></polygon>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-11" fill="white">
<use xlink:href="#path-10"></use>
</mask>
<g id="Clip-57"></g>
<polygon id="Fill-56" fill="#1089A3" mask="url(#mask-11)" points="1.09451692 2.01055385 1.43704 0.773507692 1.47525538 0.765015385 1.13131692 2.00064615"></polygon>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-13" fill="white">
<use xlink:href="#path-12"></use>
</mask>
<g id="Clip-81"></g>
<path d="M1.38891692,0.781716923 C1.39457846,0.780301538 1.39882462,0.780301538 1.40448615,0.778886154 L1.43704,0.773224615 L1.09451692,2.01027077 L1.07045538,2.01876308 C1.06337846,2.02159385 1.05347077,2.02300923 1.04356308,2.02442462 L1.38891692,0.781716923 Z" id="Fill-80" fill="#108CA7" mask="url(#mask-13)"></path>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-15" fill="white">
<use xlink:href="#path-14"></use>
</mask>
<g id="Clip-83"></g>
<path d="M1.3156,0.791341538 C1.32126154,0.791341538 1.32692308,0.789926154 1.334,0.788510769 C1.34249231,0.788510769 1.34956923,0.787095385 1.35664615,0.78568 C1.36796923,0.784264615 1.37929231,0.782849231 1.3892,0.781433846 L1.04384615,2.02414154 C1.02544615,2.02838769 1.00563077,2.03121846 0.985815385,2.03546462 L0.970246154,2.03688 L1.3156,0.791341538 Z" id="Fill-82" fill="#108FAB" mask="url(#mask-15)"></path>
</g>
<g transform="translate(14.153846, 2.933116)">
<mask id="mask-17" fill="white">
<use xlink:href="#path-16"></use>
</mask>
<g id="Clip-85"></g>
<path d="M1.3156,0.0836492308 L0.970246154,1.32918769 L0.920707692,1.33768 L1.26747692,0.0893107692 C1.28446154,0.0878953846 1.29861538,0.0850646154 1.3156,0.0836492308" id="Fill-84" fill="#1093AF" mask="url(#mask-17)"></path>
</g>
<polygon id="Fill-96" fill="#0B6173" points="12.4348615 4.50546646 11.9338154 3.95346646 12.2805846 2.70651262 12.7802154 3.25709723"></polygon>
<polygon id="Fill-98" fill="#1198B6" points="15.4211815 3.02228492 15.0758277 4.27065415 12.43472 4.505608 12.7800738 3.25723877"></polygon>
<polygon id="Fill-100" fill="#1093AF" points="12.7085969 3.26290031 12.7807815 3.25723877 12.4354277 4.505608 12.3773969 4.50136185"></polygon>
<polygon id="Fill-102" fill="#108EA9" points="12.7085969 3.26290031 12.2075508 2.71231569 12.2811508 2.70523877 12.7807815 3.25723877"></polygon>
<polygon id="Fill-104" fill="#0A5D6F" points="12.3768308 4.50136185 11.8757846 3.94936185 12.2084 2.71231569 12.7080308 3.26290031"></polygon>
<polygon id="Fill-106" fill="#1192AD" points="12.6214092 3.26148492 12.1203631 2.71090031 12.2081169 2.71231569 12.7091631 3.26290031"></polygon>
<path d="M12.5364862,3.26148492 L12.03544,2.70948492 C12.0651631,2.70948492 12.0934708,2.71090031 12.1217785,2.71090031 L12.6214092,3.26148492 L12.5364862,3.26148492" id="Fill-108" fill="#1088A2"></path>
<polygon id="Fill-109" fill="#1197B3" points="12.5364862 3.26148492 12.6214092 3.26148492 12.7091631 3.26290031 12.3765477 4.50136185 12.1840554 4.50843877 12.1741477 4.50843877 12.5195015 3.26006954"></polygon>
<polygon id="Fill-111" fill="#0B5F72" points="12.1742892 4.50815569 11.6732431 3.95615569 12.0200123 2.70920185 12.5196431 3.25978646"></polygon>
<polygon id="Fill-113" fill="#1192AD" points="12.5199262 3.26006954 12.0202954 2.70948492 12.0358646 2.70948492 12.5369108 3.26148492"></polygon>
<polygon id="Fill-115" fill="#1093AF" points="12.0817231 4.50136185 12.4242462 3.26573108 12.5204923 3.26006954 12.1737231 4.50843877 12.1581538 4.50843877"></polygon>
<polygon id="Fill-117" fill="#0A5D6F" points="12.0817231 4.50136185 11.5806769 3.95077723 11.9246154 2.71373108 12.4242462 3.26573108"></polygon>
<polygon id="Fill-119" fill="#108EA9" points="12.4245292 3.26558954 11.9248985 2.71358954 12.0197292 2.70934338 12.51936 3.259928"></polygon>
<polygon id="Fill-121" fill="#0A5B6C" points="12.0235508 4.49711569 11.5225046 3.94511569 11.8664431 2.70948492 12.3660738 3.26006954"></polygon>
<polygon id="Fill-123" fill="#108FAB" points="12.0235508 4.49711569 12.3660738 3.26006954 12.4241046 3.26573108 12.0815815 4.50136185"></polygon>
<polygon id="Fill-125" fill="#108AA5" points="12.3664985 3.26006954 11.8668677 2.70948492 11.9248985 2.71373108 12.4245292 3.26573108"></polygon>
<polygon id="Fill-127" fill="#0F839D" points="12.3207815 3.24761415 11.8197354 2.69561415 11.8664431 2.709768 12.3660738 3.26035262"></polygon>
<polygon id="Fill-129" fill="#0A596A" points="11.9772677 4.49301108 11.4762215 3.94101108 11.8102523 2.69405723 12.3112985 3.24605723"></polygon>
<path d="M12.2648738,3.24067877 L11.7652431,2.69009415 C11.7808123,2.69150954 11.7949662,2.69292492 11.80912,2.69434031 L12.3101662,3.24634031 C12.2945969,3.24492492 12.2804431,3.24350954 12.2648738,3.24067877" id="Fill-131" fill="#0E7C93"></path>
<path d="M12.3111569,3.24619877 L11.8101108,2.69419877 C11.8143569,2.69419877 11.8171877,2.69561415 11.8200185,2.69561415 L12.3210646,3.24761415 C12.3168185,3.24619877 12.3139877,3.24619877 12.3111569,3.24619877" id="Fill-132" fill="#0E7F97"></path>
<path d="M12.3207815,3.24761415 L12.3660738,3.26035262 L12.0235508,4.49739877 L11.9909969,4.494568 C11.9867508,4.494568 11.9810892,4.49315262 11.9768431,4.49315262 L12.3108738,3.24619877 C12.31512,3.24619877 12.3179508,3.24619877 12.3207815,3.24761415" id="Fill-133" fill="#108CA7"></path>
<path d="M12.2648738,3.24067877 C12.2804431,3.24350954 12.2945969,3.24492492 12.3101662,3.24634031 L11.9775508,4.49329415 C11.97472,4.49329415 11.9718892,4.49329415 11.9704738,4.49187877 C11.9534892,4.49046338 11.9365046,4.489048 11.91952,4.48621723 L12.2648738,3.24067877 Z" id="Fill-135" fill="#1089A3"></path>
<polygon id="Fill-137" fill="#0A5767" points="11.9199446 4.48607569 11.4203138 3.93407569 11.7656677 2.68995262 12.2652985 3.24053723"></polygon>
<path d="M12.2545415,3.23940492 L11.7534954,2.68882031 C11.7577415,2.68882031 11.7619877,2.68882031 11.7648185,2.69023569 L12.2644492,3.24082031 C12.2616185,3.24082031 12.2573723,3.24082031 12.2545415,3.23940492" id="Fill-139" fill="#0D7990"></path>
<path d="M12.2191569,3.23657415 L12.2545415,3.23940492 C12.2573723,3.24082031 12.2616185,3.24082031 12.2644492,3.24082031 L11.9205108,4.48635877 C11.9049415,4.483528 11.8893723,4.48211262 11.8738031,4.47928185 L12.2191569,3.23657415 Z" id="Fill-140" fill="#0F859F"></path>
<polygon id="Fill-142" fill="#0E8199" points="12.2191569 3.23657415 11.7181108 2.68598954 11.7534954 2.68882031 12.2545415 3.23940492"></polygon>
<polygon id="Fill-144" fill="#095565" points="11.8743692 4.47914031 11.3747385 3.92855569 11.7186769 2.685848 12.2197231 3.23643262"></polygon>
<polygon id="Fill-146" fill="#0E7D95" points="12.1728738 3.23374338 11.6718277 2.68174338 11.7185354 2.68598954 12.2195815 3.23657415"></polygon>
<polygon id="Fill-148" fill="#095262" points="11.82936 4.46951569 11.3283138 3.91893108 11.6722523 2.68188492 12.1732985 3.23388492"></polygon>
<path d="M11.82936,4.46951569 L12.1732985,3.23388492 L12.2185908,3.23671569 L11.8746523,4.47942338 C11.8619138,4.478008 11.8534215,4.47659262 11.8435138,4.47517723 L11.82936,4.46951569 Z" id="Fill-150" fill="#0F819B"></path>
<polygon id="Fill-152" fill="#0D758C" points="12.1515015 3.22694954 11.6518708 2.67494954 11.6731015 2.68202646 12.1727323 3.23402646"></polygon>
<polygon id="Fill-154" fill="#094E5D" points="11.7389169 4.45564492 11.2378708 3.90506031 11.5832246 2.663768 12.0828554 3.215768"></polygon>
<polygon id="Fill-156" fill="#0C6C80" points="12.0374215 3.20755877 11.5363754 2.65555877 11.5406215 2.65555877 12.0402523 3.20755877"></polygon>
<polygon id="Fill-157" fill="#084C5A" points="11.6939077 4.44602031 11.1928615 3.89402031 11.5368 2.65555877 12.0378462 3.20755877"></polygon>
<polygon id="Fill-159" fill="#084957" points="11.638 4.43087569 11.1383692 3.88029108 11.4808923 2.64466031 11.9805231 3.19666031"></polygon>
<path d="M11.9697662,3.193688 L11.46872,2.641688 C11.4729662,2.64310338 11.4772123,2.64451877 11.4814585,2.64451877 L11.9810892,3.19651877 C11.9768431,3.19510338 11.9725969,3.19510338 11.9697662,3.193688" id="Fill-161" fill="#0B6579"></path>
<polygon id="Fill-162" fill="#084755" points="11.6262523 4.43087569 11.1266215 3.87887569 11.4691446 2.64182954 11.9701908 3.19382954"></polygon>
<polygon id="Fill-164" fill="#0D738A" points="9.04558154 2.02571262 9.54521231 2.57629723 11.9697662 3.19340492 11.46872 2.64423569"></polygon>
<path d="M11.9808062,3.19651877 L11.4811754,2.64451877 C11.4995754,2.64876492 11.5179754,2.65159569 11.5377908,2.65584185 L12.0374215,3.20784185 C12.0176062,3.20359569 11.9992062,3.19934954 11.9808062,3.19651877" id="Fill-166" fill="#0C687C"></path>
<path d="M12.04096,3.20755877 L11.5399138,2.65555877 L11.5823754,2.66405108 L12.0820062,3.21605108 C12.0678523,3.21322031 12.0551138,3.21038954 12.04096,3.20755877" id="Fill-167" fill="#0C6C80"></path>
<path d="M12.0824308,3.21590954 L11.5828,2.66390954 C11.5969538,2.66674031 11.6125231,2.66815569 11.6280923,2.67098646 L12.1277231,3.22298646 C12.1121538,3.22015569 12.098,3.21732492 12.0824308,3.21590954" id="Fill-168" fill="#0D6F84"></path>
<path d="M12.1280062,3.22270338 L11.62696,2.67070338 C11.6354523,2.67211877 11.6439446,2.67353415 11.6524369,2.67494954 L12.1520677,3.22694954 C12.1435754,3.22553415 12.1350831,3.22411877 12.1280062,3.22270338" id="Fill-169" fill="#0D7288"></path>
<path d="M12.1280062,3.22270338 L11.62696,2.67070338 L12.1280062,3.22270338 Z M12.0827138,3.21562646 L11.7472677,4.42436492 L11.7840677,4.46399569 L12.1280062,3.22270338 C12.1124369,3.21987262 12.0982831,3.21704185 12.0827138,3.21562646 L12.0827138,3.21562646 Z" id="Fill-170" fill="#09505F"></path>
<path d="M12.1280062,3.22270338 C12.1350831,3.22411877 12.1435754,3.22553415 12.1520677,3.22694954 L12.1732985,3.23402646 L11.82936,4.46965723 L11.8038831,4.46824185 L11.7840677,4.46399569 L12.1280062,3.22270338 Z" id="Fill-172" fill="#0E7E97"></path>
<path d="M11.7389169,4.45564492 L12.0828554,3.215768 C12.0970092,3.21718338 12.1125785,3.22001415 12.1281477,3.22284492 L11.7842092,4.46413723 C11.7757169,4.46272185 11.7672246,4.46130646 11.7587323,4.45989108 C11.7516554,4.45847569 11.7445785,4.45706031 11.7389169,4.45564492" id="Fill-174" fill="#0E7B92"></path>
<path d="M12.0374215,3.20755877 L12.0402523,3.20755877 C12.0544062,3.21038954 12.0671446,3.21322031 12.0812985,3.21605108 L11.7387754,4.455928 C11.7217908,4.45309723 11.7076369,4.44885108 11.6934831,4.44602031 L12.0374215,3.20755877 Z" id="Fill-176" fill="#0D778E"></path>
<path d="M11.638,4.43087569 L11.9805231,3.19666031 C11.9989231,3.19949108 12.0187385,3.20373723 12.0371385,3.20798338 L11.6946154,4.44644492 C11.6847077,4.44361415 11.6748,4.44219877 11.6663077,4.439368 L11.638,4.43087569 Z" id="Fill-178" fill="#0D7389"></path>
<path d="M11.9808062,3.19651877 L11.6382831,4.43073415 L11.62696,4.43073415 L11.9694831,3.193688 C11.9737292,3.19510338 11.9779754,3.19510338 11.9808062,3.19651877" id="Fill-180" fill="#0C7085"></path>
<polygon id="Fill-184" fill="#084755" points="9.25576615 4.72244492 8.75472 4.17044492 9.09865846 2.93198338 9.59970462 3.48398338"></polygon>
<polygon id="Fill-186" fill="#084C5A" points="9.22745846 4.74325108 8.72641231 4.19125108 9.07176615 2.94995877 9.57139692 3.50054338"></polygon>
<polygon id="Fill-188" fill="#094E5D" points="9.21429538 4.75004492 8.71324923 4.19804492 9.05860308 2.95533723 9.55823385 3.50733723"></polygon>
<polygon id="Fill-190" fill="#09505F" points="9.18726154 4.76108492 8.68763077 4.20908492 9.03156923 2.96637723 9.53261538 3.51837723"></polygon>
<polygon id="Fill-192" fill="#095262" points="9.16178462 4.77085108 8.66215385 4.21885108 9.00609231 2.97614338 9.50713846 3.526728"></polygon>
<polygon id="Fill-194" fill="#095565" points="9.12371077 4.78189108 8.62408 4.22989108 8.96801846 2.985768 9.46906462 3.537768"></polygon>
<polygon id="Fill-196" fill="#0A5767" points="9.08648615 4.79024185 8.58544 4.23824185 8.93079385 2.99411877 9.43184 3.54611877"></polygon>
<polygon id="Fill-198" fill="#0A596A" points="9.03666462 4.79986646 8.53703385 4.24786646 8.88238769 3.002328 9.38201846 3.554328"></polygon>
<polygon id="Fill-200" fill="#1088A2" points="9.30756923 3.57102954 8.80652308 3.01902954 8.86455385 3.00629108 9.3656 3.55687569"></polygon>
<polygon id="Fill-202" fill="#0A5B6C" points="9.23425231 3.83372492 8.73462154 3.28172492 8.80680615 3.01987877 9.30785231 3.57046338"></polygon>
<polygon id="Fill-204" fill="#108EA9" points="9.27020308 3.56834031 8.77057231 3.01634031 8.80737231 3.01917108 9.30700308 3.57117108"></polygon>
<g transform="translate(7.784615, 2.225423)">
<path d="M1.48629538,1.34008615 L0.985249231,0.789501538 C1.01638769,0.786670769 1.04469538,0.78384 1.07158769,0.781009231 L1.57263385,1.33159385 C1.54574154,1.33584 1.51601846,1.33867077 1.48629538,1.34008615" id="Fill-206" fill="#0D6E84"></path>
<path d="M1.57206769,1.33187692 L1.07102154,0.781292308 C1.07385231,0.781292308 1.07668308,0.779876923 1.07951385,0.779876923 L1.58056,1.33187692 L1.57206769,1.33187692" id="Fill-207" fill="#0C6B80"></path>
</g>
<g transform="translate(7.784615, 2.225423)">
<polygon id="Fill-208" fill="#0F829B" points="1.58027692 1.33187692 1.07923077 0.779876923 1.08064615 0.779876923"></polygon>
<path d="M1.58098462,1.33187692 L1.07993846,0.779876923 C1.0856,0.778461538 1.09126154,0.778461538 1.09692308,0.777046154 L1.59796923,1.32904615 C1.59230769,1.33046154 1.58664615,1.33046154 1.58098462,1.33187692" id="Fill-209" fill="#0E7E96"></path>
</g>
<path d="M9.38216,3.55446954 L8.88111385,3.00246954 C8.89951385,3.00105415 8.91508308,2.99822338 8.93065231,2.99397723 L9.43169846,3.54597723 C9.41471385,3.548808 9.39914462,3.55163877 9.38216,3.55446954" id="Fill-210" fill="#0E7B93"></path>
<path d="M9.43127385,3.54626031 L8.93022769,2.99426031 C8.94438154,2.99284492 8.95712,2.98859877 8.96844308,2.985768 L9.46807385,3.537768 C9.45675077,3.54059877 9.44401231,3.54342954 9.43127385,3.54626031" id="Fill-211" fill="#0E788F"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M0.976332308,1.31248615 L0.475286154,0.760486154 C0.485193846,0.759070769 0.495101538,0.75624 0.503593846,0.753409231 L1.00464,1.30540923 C0.994732308,1.30824 0.98624,1.30965538 0.976332308,1.31248615" id="Fill-212" fill="#0D758C"></path>
<path d="M1.00393231,1.30555077 L0.502886154,0.753550769 C0.507132308,0.752135385 0.509963077,0.75072 0.514209231,0.75072 L1.01384,1.30130462 L1.00393231,1.30555077" id="Fill-213" fill="#0D7288"></path>
</g>
<path d="M9.50657231,3.52686954 L9.00552615,2.97628492 C9.01543385,2.97345415 9.02392615,2.97062338 9.03241846,2.96637723 L9.53204923,3.51837723 C9.52355692,3.521208 9.51506462,3.52403877 9.50657231,3.52686954" id="Fill-214" fill="#0D6F84"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.03988308,1.29309538 L0.538836923,0.741095385 C0.544498462,0.73968 0.548744615,0.738264615 0.552990769,0.736849231 L1.05262154,1.28743385 C1.04837538,1.28884923 1.04412923,1.29168 1.03988308,1.29309538" id="Fill-215" fill="#0C6C81"></path>
<path d="M1.05304615,1.28757538 L0.552,0.736990769 C0.557661538,0.73416 0.561907692,0.732744615 0.566153846,0.729913846 L1.06578462,1.28191385 C1.06153846,1.28332923 1.05729231,1.28616 1.05304615,1.28757538" id="Fill-216" fill="#0C697D"></path>
</g>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.06620923,1.28205538 L0.565163077,0.730055385 C0.570824615,0.72864 0.575070769,0.725809231 0.579316923,0.724393846 L1.07894769,1.27497846 C1.07470154,1.27780923 1.07045538,1.27922462 1.06620923,1.28205538" id="Fill-217" fill="#0C667A"></path>
<polygon id="Fill-218" fill="#0B6376" points="1.07852308 1.27512 0.578892308 0.724535385 0.578892308 0.724535385"></polygon>
</g>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.09310154,1.26691077 L0.592055385,0.716326154 C0.593470769,0.714910769 0.594886154,0.714910769 0.594886154,0.714910769 L1.09593231,1.26549538 C1.09451692,1.26691077 1.09310154,1.26691077 1.09310154,1.26691077" id="Fill-219" fill="#0B5D6F"></path>
<path d="M1.09579077,1.26549538 L0.594744615,0.714910769 C0.598990769,0.71208 0.603236923,0.709249231 0.606067692,0.706418462 L1.10711385,1.25841846 C1.10286769,1.26124923 1.09862154,1.26266462 1.09579077,1.26549538" id="Fill-220" fill="#0A5A6C"></path>
</g>
<polygon id="Fill-221" fill="#084957" points="9.08507077 2.94217415 9.08082462 2.96057415 9.57196308 3.50125108 9.23227077 4.72414338 9.24076308 4.73405108 9.58611692 3.49275877"></polygon>
<path d="M9.57153846,3.50054338 L9.07190769,2.94995877 C9.07615385,2.947128 9.0804,2.94429723 9.08464615,2.94146646 L9.58569231,3.49205108 C9.58003077,3.49488185 9.57578462,3.49771262 9.57153846,3.50054338" id="Fill-223" fill="#0B6072"></path>
<g transform="translate(8.492308, 2.225423)">
<polygon id="Fill-224" fill="#0A5868" points="1.10697231 1.25856 0.605926154 0.70656 0.607341538 0.70656"></polygon>
<path d="M1.10697231,1.25856 L0.607341538,0.70656 L0.617249231,0.698067692 L1.11688,1.25006769 C1.11404923,1.25289846 1.11121846,1.25572923 1.10697231,1.25856" id="Fill-225" fill="#095565"></path>
<polygon id="Fill-226" fill="#095262" points="1.11730462 1.25020923 0.617673846 0.698209231 0.62192 0.693963077 1.12155077 1.24596308"></polygon>
</g>
<path d="M9.62956923,3.45355262 L9.12852308,2.90155262 C9.13135385,2.89872185 9.13276923,2.89589108 9.1356,2.89306031 L9.63523077,3.44364492 C9.63381538,3.44647569 9.63098462,3.45072185 9.62956923,3.45355262" id="Fill-227" fill="#095060"></path>
<path d="M9.12923077,2.90211877 L9.12215385,2.93042646 L9.61329231,3.47110338 C9.60904615,3.47534954 9.6048,3.47959569 9.59913846,3.48384185 L9.48873846,3.88156492 L9.50572308,3.90138031 L9.63027692,3.45411877 L9.12923077,2.90211877 Z" id="Fill-228" fill="#094D5C"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.12140923,1.24610462 L0.621778462,0.694104615 C0.621778462,0.692689231 0.623193846,0.692689231 0.624609231,0.691273846 L1.12424,1.24327385 C1.12282462,1.24327385 1.12282462,1.24468923 1.12140923,1.24610462" id="Fill-230" fill="#09505F"></path>
<path d="M1.12494769,1.24341538 L0.623901538,0.691415385 C0.626732308,0.688584615 0.628147692,0.687169231 0.630978462,0.684338462 L1.13060923,1.23633846 C1.12919385,1.23775385 1.12636308,1.24058462 1.12494769,1.24341538" id="Fill-231" fill="#094D5C"></path>
<path d="M1.13103385,1.23648 L0.629987692,0.68448 C0.632818462,0.681649231 0.634233846,0.678818462 0.637064615,0.677403077 L1.13669538,1.22798769 C1.13386462,1.23081846 1.13244923,1.23364923 1.13103385,1.23648" id="Fill-232" fill="#084A58"></path>
</g>
<path d="M9.59928,3.48398338 L9.26524923,4.69130646 L9.27374154,4.69979877 L9.61343385,3.47124492 C9.60918769,3.47549108 9.60494154,3.47973723 9.59928,3.48398338" id="Fill-233" fill="#084552"></path>
<polygon id="Fill-235" fill="#0A5B6C" points="8.96405538 4.80680185 8.46300923 4.25621723 8.73476308 3.28243262 9.23439385 3.83443262"></polygon>
<path d="M9.59928,3.48398338 C9.60494154,3.47973723 9.60918769,3.47549108 9.61343385,3.47124492 L9.27374154,4.69979877 L9.25534154,4.72244492 L9.59928,3.48398338 Z" id="Fill-237" fill="#0C7085"></path>
<path d="M9.62900308,3.45355262 L9.62475692,3.47195262 L9.29072615,4.67644492 C9.28931077,4.68210646 9.28506462,4.687768 9.28223385,4.69201415 L9.27374154,4.70050646 L9.61343385,3.47195262 C9.62051077,3.46629108 9.62475692,3.46062954 9.62900308,3.45355262" id="Fill-239" fill="#0C6D81"></path>
<path d="M9.59928,3.48398338 L9.25534154,4.72244492 L9.24118769,4.733768 L9.58512615,3.49247569 C9.59078769,3.48964492 9.59503385,3.48681415 9.59928,3.48398338" id="Fill-241" fill="#0D7389"></path>
<path d="M9.57153846,3.50054338 C9.57578462,3.49771262 9.58003077,3.49488185 9.58569231,3.49205108 L9.24175385,4.73334338 L9.23326154,4.73900492 C9.23043077,4.74042031 9.22901538,4.74183569 9.2276,4.74325108 L9.57153846,3.50054338 Z" id="Fill-243" fill="#0D778E"></path>
<path d="M9.57153846,3.50054338 L9.2276,4.74325108 C9.22618462,4.74325108 9.22476923,4.74466646 9.22335385,4.74466646 L9.21769231,4.74891262 C9.21627692,4.74891262 9.21486154,4.750328 9.21486154,4.750328 L9.5588,3.50762031 C9.56304615,3.50478954 9.56729231,3.50337415 9.57153846,3.50054338" id="Fill-245" fill="#0E7B92"></path>
<path d="M9.21429538,4.75004492 C9.20580308,4.75429108 9.19731077,4.75712185 9.18740308,4.761368 L9.53275692,3.51866031 C9.54124923,3.51441415 9.54974154,3.51158338 9.55823385,3.50733723 L9.21429538,4.75004492 Z" id="Fill-247" fill="#0E7E97"></path>
<path d="M9.16178462,4.77085108 L9.50713846,3.526728 C9.51563077,3.52389723 9.52412308,3.52106646 9.53261538,3.51823569 L9.18726154,4.76094338 C9.18584615,4.76235877 9.18443077,4.76235877 9.18301538,4.76377415 L9.17027692,4.76802031 C9.16744615,4.76943569 9.16461538,4.76943569 9.16178462,4.77085108" id="Fill-249" fill="#0F819B"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.13726154,1.22812923 L0.636215385,0.676129231 C0.639046154,0.673298462 0.640461538,0.670467692 0.643292308,0.667636923 L1.14292308,1.21822154 C1.14150769,1.22105231 1.13867692,1.22529846 1.13726154,1.22812923" id="Fill-251" fill="#095060"></path>
<path d="M1.14278154,1.21850462 L0.643150769,0.666504615 C0.650227692,0.652350769 0.654473846,0.635366154 0.651643077,0.616966154 L1.15268923,1.16896615 C1.15410462,1.18736615 1.15127385,1.20293538 1.14278154,1.21850462" id="Fill-252" fill="#094D5D"></path>
</g>
<path d="M9.12371077,4.78189108 L9.46906462,3.537768 C9.48180308,3.53493723 9.49454154,3.53069108 9.50728,3.52644492 L9.16192615,4.770568 C9.15201846,4.77339877 9.14069538,4.77764492 9.12795692,4.78047569 C9.12654154,4.78047569 9.12512615,4.78189108 9.12371077,4.78189108" id="Fill-253" fill="#0F859F"></path>
<path d="M9.08648615,4.79024185 L9.43184,3.54611877 C9.44457846,3.543288 9.45731692,3.54045723 9.46864,3.53762646 L9.12328615,4.78174954 C9.11196308,4.78458031 9.09922462,4.78741108 9.08648615,4.79024185" id="Fill-255" fill="#1089A3"></path>
<path d="M9.03666462,4.79986646 L9.38201846,3.554328 C9.39900308,3.55149723 9.41598769,3.54866646 9.43155692,3.54583569 L9.08620308,4.78995877 C9.08195692,4.79137415 9.07912615,4.79137415 9.07488,4.79278954 C9.06638769,4.79420492 9.05789538,4.79562031 9.04798769,4.79845108 C9.04515692,4.79845108 9.04091077,4.79845108 9.03666462,4.79986646" id="Fill-257" fill="#108CA7"></path>
<path d="M9.30756923,3.57102954 L9.3656,3.55687569 C9.36984615,3.55546031 9.37550769,3.55546031 9.38258462,3.55404492 L9.03723077,4.79958338 C9.03156923,4.79958338 9.02732308,4.80099877 9.02166154,4.80241415 L8.96363077,4.80666031 L9.23396923,3.83429108 L9.30756923,3.57102954 Z" id="Fill-259" fill="#108FAB"></path>
<polygon id="Fill-261" fill="#094B59" points="9.27020308 3.56834031 8.77057231 3.01634031 8.77057231 3.01492492 9.27020308 3.56550954"></polygon>
<path d="M9.27020308,3.56834031 L9.27020308,3.56550954 C9.30417231,3.56409415 9.33531077,3.56126338 9.36503385,3.55701723 L9.30700308,3.57117108 L9.27020308,3.56834031 Z" id="Fill-263" fill="#094B59"></path>
<polygon id="Fill-267" fill="#108EA9" points="9.26128615 3.56692492 8.76024 3.01492492 8.77014769 3.01634031 9.26977846 3.56834031"></polygon>
<polygon id="Fill-269" fill="#1093AF" points="9.23425231 3.83372492 8.96391385 4.80609415 8.91437538 4.81458646 9.26114462 3.56763262 9.26963692 3.569048 9.30785231 3.57046338"></polygon>
<path d="M11.9537723,0.745780308 L11.9537723,0.750026462 L11.9523569,0.750026462 L11.9537723,0.747195692 C11.9537723,0.747195692 11.9537723,0.747195692 11.9537723,0.745780308" id="Fill-300" fill="#08434F"></path>
<path d="M11.92136,0.783146462 L11.5788369,2.01877723 L11.5519446,2.03010031 L11.8944677,0.795884923 C11.8987138,0.793054154 11.9015446,0.791638769 11.9043754,0.788808 L11.92136,0.783146462 Z" id="Fill-302" fill="#0D778E"></path>
<path d="M11.9621231,0.733324923 L11.9692,0.727663385 L11.6266769,1.96329415 L11.6096923,1.98594031 L11.9536308,0.750309538 L11.9536308,0.746063385 C11.9550462,0.744648 11.9564615,0.743232615 11.9564615,0.741817231 C11.9592923,0.738986462 11.9607077,0.736155692 11.9621231,0.733324923" id="Fill-313" fill="#0B697D"></path>
<path d="M11.8888062,0.798291077 C11.8902215,0.796875692 11.8930523,0.795460308 11.8944677,0.795460308 L11.5519446,2.02967569 L11.5377908,2.03958338 L11.8817292,0.803952615 L11.8888062,0.798291077 Z" id="Fill-319" fill="#0E7B92"></path>
<polygon id="Fill-323" fill="#0E7E97" points="11.8549785 0.813577231 11.8818708 0.803669538 11.5379323 2.03930031 11.5124554 2.05062338"></polygon>
<polygon id="Fill-327" fill="#0F819B" points="11.4859877 2.060248 11.8299262 0.823201846 11.8554031 0.813294154 11.51288 2.05034031"></polygon>
<path d="M11.7914277,0.832968 C11.7985046,0.831552615 11.8069969,0.828721846 11.8140738,0.827306462 L11.8296431,0.823060308 L11.4857046,2.06010646 L11.4489046,2.06859877 L11.7914277,0.832968 Z" id="Fill-333" fill="#0F859F"></path>
<path d="M11.7914277,0.832968 L11.2903815,0.282383385 L11.7914277,0.832968 Z M11.7546277,0.842875692 L11.4220123,2.04029108 L11.4489046,2.06859877 L11.7914277,0.832968 C11.7801046,0.837214154 11.7673662,0.840044923 11.7546277,0.842875692 L11.7546277,0.842875692 Z" id="Fill-356" fill="#095565"></path>
<path d="M11.4092738,2.08515877 L11.7546277,0.842451077 C11.7673662,0.839620308 11.7801046,0.836789538 11.7914277,0.832543385 L11.4489046,2.06817415 L11.4262585,2.08091262 C11.4205969,2.082328 11.4149354,2.08374338 11.4092738,2.08515877" id="Fill-358" fill="#1089A3"></path>
<path d="M11.3594523,2.09492492 L11.7048062,0.850801846 C11.7217908,0.847971077 11.7387754,0.845140308 11.7543446,0.842309538 L11.4089908,2.08501723 C11.3934215,2.087848 11.3764369,2.09209415 11.3594523,2.09492492" id="Fill-360" fill="#108CA7"></path>
<path d="M11.6310646,0.860568 C11.6423877,0.860568 11.6522954,0.857737231 11.6622031,0.856321846 C11.6664492,0.856321846 11.6706954,0.856321846 11.6749415,0.854906462 C11.6848492,0.853491077 11.6947569,0.852075692 11.7046646,0.850660308 L11.3593108,2.09478338 C11.3508185,2.09619877 11.3437415,2.09902954 11.3366646,2.09902954 L11.2871262,2.10469108 L11.6310646,0.860568 Z" id="Fill-365" fill="#108FAB"></path>
<path d="M11.6310646,0.860568 L11.2871262,2.10469108 L11.2489108,2.11318338 L11.59568,0.864814154 C11.6070031,0.863398769 11.6197415,0.861983385 11.6310646,0.860568" id="Fill-367" fill="#1093AF"></path>
<path d="M5.19899077,3.15773723 L5.70003692,3.70973723 C5.68446769,3.70407569 5.67031385,3.69982954 5.65474462,3.694168 L5.31788308,4.908568 L5.35468308,4.94961415 L5.70003692,3.70973723 L5.19899077,3.15773723 Z" id="Fill-481" fill="#07424F"></path>
<path d="M1.60660308,2.81634646 L1.95054154,1.57222338 C1.96328,1.57505415 1.97601846,1.57930031 1.98875692,1.58213108 C1.99017231,1.58213108 1.99300308,1.58354646 1.99583385,1.58354646 L1.65048,2.82908492 C1.64481846,2.82766954 1.63915692,2.82625415 1.63349538,2.82342338 L1.61651077,2.81917723 L1.60660308,2.81634646 Z" id="Fill-561" fill="#0C7085"></path>
<path d="M1.31843077,0.983564923 L1.81947692,1.53414954 C1.81523077,1.53414954 1.8124,1.53273415 1.80956923,1.53131877 L1.57178462,1.26805723 L1.80956923,1.53131877 C1.79824615,1.52707262 1.78692308,1.52282646 1.7756,1.51858031 L1.43873846,2.72873415 L1.47553846,2.77119569 L1.81947692,1.53414954 L1.31843077,0.983564923 Z" id="Fill-585" fill="#07404D"></path>
<path d="M15.68232,2.71967569 C15.7955508,2.78619877 15.8281046,2.85130646 15.7898892,2.90367569 C15.6596738,2.98293723 15.6129662,2.99426031 15.5577662,3.004168 C15.5195508,3.01124492 15.4940738,3.01407569 15.4700123,3.01690646 C15.4530277,3.01832185 15.4374585,3.02115262 15.4204738,3.022568 L12.7807815,3.25752185 C12.6604738,3.26601415 12.5260123,3.26459877 12.3858892,3.25327569 C12.2471815,3.24195262 12.1042277,3.22213723 11.9697662,3.19382954 L9.54521231,2.57530646 L9.64428923,3.39481415 C9.64712,3.41604492 9.64145846,3.43586031 9.63013538,3.45426031 C9.49425846,3.53069108 9.48152,3.53493723 9.46878154,3.537768 C9.45745846,3.54059877 9.44472,3.54342954 9.43056615,3.54626031 C9.41499692,3.54909108 9.39942769,3.55192185 9.38244308,3.55475262 C9.33573538,3.56182954 9.30459692,3.56466031 9.27062769,3.56607569 L6.62102769,3.80244492 C6.58988923,3.80669108 6.55875077,3.80952185 6.52619692,3.81093723 C6.41296615,3.813768 6.31955077,3.81235262 6.22613538,3.80669108 C5.94730462,3.78404492 5.66705846,3.71752185 5.50570462,3.63259877 C5.42078154,3.58306031 5.38398154,3.53493723 5.38539692,3.49247569 C5.38822769,3.41321415 5.52410462,3.34952185 5.76613538,3.33112185 L6.84465846,3.23062954 L7.62170462,3.15986031 L8.01093538,3.12447569 L7.89770462,2.16201415 L5.03721231,1.45149108 L2.78392,1.64398338 C2.72447385,1.64964492 2.66219692,1.65247569 2.59708923,1.65106031 C2.57585846,1.65106031 2.55604308,1.65106031 2.53339692,1.64964492 C2.47819692,1.64822954 2.43856615,1.64681415 2.39752,1.642568 C2.11727385,1.62275262 1.83419692,1.56047569 1.67850462,1.47555262 C1.58367385,1.42035262 1.54545846,1.36515262 1.55819692,1.31702954 C1.57659692,1.24484492 1.70681231,1.18681415 1.93185846,1.16133723 L4.58428923,0.926383385 C4.69468923,0.919306462 4.82207385,0.920721846 4.95087385,0.929214154 C5.09807385,0.940537231 5.24952,0.966014154 5.37973538,0.999983385 L7.51413538,1.52933723 L7.82976615,1.60859877 L7.71936615,0.790506462 C7.72078154,0.702752615 7.85524308,0.631983385 8.09161231,0.616414154 L10.7313046,0.381460308 C10.8544431,0.371552615 10.9889046,0.372968 11.1219508,0.382875692 C11.4078585,0.404106462 11.68952,0.469214154 11.8452123,0.562629538 C11.9556123,0.626321846 11.9895815,0.688598769 11.9570277,0.742383385 C11.8678585,0.807491077 11.8437969,0.817398769 11.8140738,0.827306462 C11.7801046,0.837214154 11.7673662,0.840044923 11.7546277,0.842875692 C11.7376431,0.845706462 11.7220738,0.848537231 11.7036738,0.851368 C11.6810277,0.855614154 11.6569662,0.858444923 11.6314892,0.861275692 C11.6187508,0.862691077 11.6074277,0.862691077 11.5946892,0.864106462 L9.35413538,1.05942954 L9.47727385,2.02330646 L10.1962892,2.20447569 L12.3363508,2.746568 L14.5698277,2.53850646 C14.6915508,2.52859877 14.8260123,2.53001415 14.9576431,2.53992185 C15.24072,2.562568 15.5195508,2.62767569 15.68232,2.71967569" id="Fill-587" fill="#18D6FF"></path>
<path d="M9.54535385,2.57587262 L11.9699077,3.19439569 L11.6259692,4.43144185 L9.50572308,3.902088 L9.63027692,3.45341108 C9.6416,3.43501108 9.64726154,3.41661108 9.64443077,3.39396492 L9.54535385,2.57587262 Z" id="Fill-589" fill="#0E7A92"></path>
<polygon id="Fill-591" fill="#1198B6" points="9.26128615 3.56692492 8.91451692 4.81529415 6.27482462 5.050248 6.62017846 3.80187877"></polygon>
<g transform="translate(5.661538, 3.640808)">
<mask id="mask-19" fill="white">
<use xlink:href="#path-18"></use>
</mask>
<g id="Clip-594"></g>
<path d="M0.887163077,0.168006154 C0.911224615,0.166590769 0.935286154,0.16376 0.959347692,0.160929231 L0.613993846,1.40929846 C0.589932308,1.41212923 0.565870769,1.41354462 0.541809231,1.41354462 L0.887163077,0.168006154 Z" id="Fill-593" fill="#1093AF" mask="url(#mask-19)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-21" fill="white">
<use xlink:href="#path-20"></use>
</mask>
<g id="Clip-596"></g>
<path d="M1.57956923,0.169421538 C1.58381538,0.168006154 1.58947692,0.168006154 1.59513846,0.168006154 L1.24978462,1.41354462 C1.23421538,1.41496 1.22006154,1.41496 1.20590769,1.41496 L1.06012308,1.41354462 L1.40264615,0.176498462 L1.51446154,0.172252308 C1.53003077,0.170836923 1.54418462,0.170836923 1.55833846,0.169421538 L1.57249231,0.169421538 L1.57956923,0.169421538 Z" id="Fill-595" fill="#1197B3" mask="url(#mask-21)"></path>
</g>
<polygon id="Fill-597" fill="#1198B6" points="11.5951138 0.864672615 11.2483446 2.11304185 10.1967138 2.20362646 9.47769846 2.02245723 9.35456 1.05999569"></polygon>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-23" fill="white">
<use xlink:href="#path-22"></use>
</mask>
<g id="Clip-600"></g>
<polygon id="Fill-599" fill="#1093AF" mask="url(#mask-23)" points="0.967981538 1.40646769 1.31050462 0.169421538 1.40392 0.176498462 1.05998154 1.41354462"></polygon>
</g>
<polygon id="Fill-601" fill="#0D7991" points="6.84522462 3.23105415 6.34417846 2.68046954 7.12122462 2.60970031 7.62227077 3.15886954"></polygon>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-25" fill="white">
<use xlink:href="#path-24"></use>
</mask>
<g id="Clip-604"></g>
<polygon id="Fill-603" fill="#108FAB" mask="url(#mask-25)" points="0.909950769 1.40094769 1.25247385 0.165316923 1.31050462 0.169563077 0.967981538 1.40660923"></polygon>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-27" fill="white">
<use xlink:href="#path-26"></use>
</mask>
<g id="Clip-606"></g>
<polygon id="Fill-605" fill="#108CA7" mask="url(#mask-27)" points="1.19543385 0.161070769 1.25346462 0.165316923 0.909526154 1.40094769 0.864233846 1.39811692"></polygon>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-29" fill="white">
<use xlink:href="#path-28"></use>
</mask>
<g id="Clip-608"></g>
<polygon id="Fill-607" fill="#1089A3" mask="url(#mask-29)" points="0.805636923 1.39401231 1.14957538 0.156966154 1.19486769 0.161212308 0.863667692 1.39825846"></polygon>
</g>
<polygon id="Fill-609" fill="#0A5869" points="7.89841231 2.16258031 8.01022769 3.12504185 7.62241231 3.15901108"></polygon>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-31" fill="white">
<use xlink:href="#path-30"></use>
</mask>
<g id="Clip-614"></g>
<path d="M0.75992,1.38849231 L1.10385846,0.145784615 C1.11235077,0.1472 1.11942769,0.148615385 1.12792,0.150030769 L1.14915077,0.157107692 L0.805212308,1.39415385 L0.789643077,1.39273846 L0.75992,1.38849231 Z" id="Fill-613" fill="#0F859F" mask="url(#mask-31)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-33" fill="white">
<use xlink:href="#path-32"></use>
</mask>
<g id="Clip-616"></g>
<path d="M1.05856615,0.138990769 C1.07413538,0.141821538 1.08828923,0.144652308 1.10385846,0.146067692 L0.75992,1.38877538 C0.744350769,1.38594462 0.730196923,1.38452923 0.714627692,1.38169846 L1.05856615,0.138990769 Z" id="Fill-615" fill="#0F819B" mask="url(#mask-33)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-35" fill="white">
<use xlink:href="#path-34"></use>
</mask>
<g id="Clip-618"></g>
<path d="M1.04328,0.13616 C1.04752615,0.137575385 1.05318769,0.138990769 1.05884923,0.138990769 L0.714910769,1.38169846 C0.705003077,1.38028308 0.695095385,1.37886769 0.685187692,1.37603692 L0.669618462,1.37037538 L1.01355692,0.134744615 L1.04328,0.13616 Z" id="Fill-617" fill="#0E7E97" mask="url(#mask-35)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-37" fill="white">
<use xlink:href="#path-36"></use>
</mask>
<g id="Clip-620"></g>
<path d="M0.967981538,0.123704615 L0.970812308,0.123704615 C0.979304615,0.12512 0.987796923,0.126535385 0.996289231,0.129366154 L1.01327385,0.135027692 L0.669335385,1.37065846 L0.639612308,1.36924308 C0.635366154,1.36782769 0.63112,1.36782769 0.628289231,1.36641231 C0.626873846,1.36641231 0.625458462,1.36641231 0.624043077,1.36499692 L0.967981538,0.123704615 Z" id="Fill-619" fill="#0E7B92" mask="url(#mask-37)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-39" fill="white">
<use xlink:href="#path-38"></use>
</mask>
<g id="Clip-622"></g>
<path d="M0.922406154,0.115495385 L0.935144615,0.116910769 C0.942221538,0.118326154 0.950713846,0.119741538 0.957790769,0.121156923 C0.962036923,0.122572308 0.964867692,0.122572308 0.967698462,0.123987692 L0.62376,1.36528 C0.620929231,1.36528 0.618098462,1.36528 0.615267692,1.36386462 C0.613852308,1.36386462 0.612436923,1.36386462 0.611021538,1.36244923 L0.579883077,1.35254154 L0.922406154,0.115495385 Z" id="Fill-621" fill="#0D778E" mask="url(#mask-39)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-41" fill="white">
<use xlink:href="#path-40"></use>
</mask>
<g id="Clip-624"></g>
<path d="M0.878104615,0.104455385 C0.890843077,0.107286154 0.902166154,0.110116923 0.912073846,0.111532308 L0.921981538,0.115778462 L0.579458462,1.35282462 L0.549735385,1.34999385 C0.546904615,1.34857846 0.544073846,1.34857846 0.539827692,1.34716308 C0.538412308,1.34716308 0.535581538,1.34716308 0.534166154,1.34574769 L0.878104615,0.104455385 Z" id="Fill-623" fill="#0D7389" mask="url(#mask-41)"></path>
</g>
<g transform="translate(4.246154, 3.640808)">
<mask id="mask-43" fill="white">
<use xlink:href="#path-42"></use>
</mask>
<g id="Clip-626"></g>
<path d="M1.54092923,0.0961046154 L1.56216,0.0989353846 C1.56782154,0.100350769 1.57348308,0.100350769 1.57914462,0.101766154 C1.58056,0.103181538 1.58339077,0.103181538 1.58622154,0.104596923 L1.24228308,1.34588923 C1.23945231,1.34588923 1.23520615,1.34447385 1.23237538,1.34447385 L1.21680615,1.34022769 L1.19699077,1.33315077 L1.54092923,0.0961046154 Z" id="Fill-625" fill="#0C7085" mask="url(#mask-43)"></path>
</g>
<polygon id="Fill-627" fill="#0C6D81" points="5.40011692 4.95881415 5.74264 3.721768 5.78651692 3.73733723 5.44399385 4.97438338"></polygon>
<path d="M5.35510769,4.94918954 L5.69904615,3.70931262 C5.71178462,3.71355877 5.72593846,3.71638954 5.73867692,3.72063569 L5.74292308,3.72205108 L5.4004,4.95909723 L5.37633846,4.95768185 C5.36926154,4.95485108 5.36218462,4.95202031 5.35510769,4.94918954" id="Fill-629" fill="#0B697D"></path>
<path d="M5.65502769,3.69402646 C5.66918154,3.699688 5.68475077,3.70393415 5.69890462,3.70959569 L5.35496615,4.94947262 C5.34081231,4.94522646 5.32524308,4.94098031 5.31108923,4.93531877 L5.65502769,3.69402646 Z" id="Fill-631" fill="#0B6579"></path>
<path d="M5.60464,3.67605108 C5.62020923,3.683128 5.63719385,3.68878954 5.65559385,3.69445108 L5.31165538,4.93574338 C5.29891692,4.93149723 5.28759385,4.92725108 5.27627077,4.92158954 L5.25787077,4.91168185 L5.60180923,3.67463569 L5.60464,3.67605108 Z" id="Fill-633" fill="#0B6275"></path>
<path d="M5.20451077,4.88974338 L5.54703385,3.65269723 C5.56260308,3.65977415 5.58100308,3.66685108 5.59798769,3.673928 L5.60081846,3.67534338 L5.25829538,4.91238954 L5.23706462,4.90531262 C5.23564923,4.90531262 5.23423385,4.90531262 5.23281846,4.90389723 C5.22291077,4.89965108 5.21300308,4.89540492 5.20451077,4.88974338" id="Fill-635" fill="#0B5F71"></path>
<path d="M5.54731692,3.65255569 L5.20479385,4.88960185 C5.19064,4.88252492 5.17507077,4.875448 5.16233231,4.86837108 L5.04485538,4.71692492 L5.38454769,3.49261723 C5.38313231,3.53507877 5.42134769,3.58320185 5.50485538,3.63132492 C5.51759385,3.63840185 5.53316308,3.64547877 5.54731692,3.65255569" id="Fill-639" fill="#0A5B6D"></path>
<path d="M7.51413538,1.52947877 L7.72078154,0.786401846 C7.72078154,0.787817231 7.71936615,0.789232615 7.71936615,0.790648 L7.51413538,1.52947877 Z" id="Fill-645" fill="#063843"></path>
<polygon id="Fill-705" fill="#0E7A92" points="5.03650462 1.45078338 7.89841231 2.16272185 7.62241231 3.15915262 6.84536615 3.23133723 4.69256615 2.68641415"></polygon>
<polygon id="Fill-713" fill="#1198B6" points="5.03650462 1.45078338 4.69256615 2.68641415 2.43785846 2.89306031 2.78321231 1.64469108"></polygon>
<path d="M2.72277538,1.65120185 L2.78363692,1.64412492 L2.43686769,2.89249415 C2.41846769,2.89390954 2.39865231,2.89532492 2.37742154,2.89674031 L2.72277538,1.65120185 Z" id="Fill-715" fill="#1093AF"></path>
<path d="M2.59694769,1.65120185 L2.61110154,1.65120185 L2.66064,1.65120185 L2.72291692,1.65120185 L2.37756308,2.89674031 C2.35491692,2.89815569 2.33085538,2.89815569 2.30679385,2.89957108 L2.18790154,2.89674031 L2.53467077,1.64978646 C2.55165538,1.65120185 2.56722462,1.65120185 2.58420923,1.65120185 L2.59694769,1.65120185 Z" id="Fill-717" fill="#1197B3"></path>
<polygon id="Fill-719" fill="#1093AF" points="2.51811077 1.64978646 2.53368 1.64978646 2.18832615 2.89674031 2.09632615 2.88966338 2.43884923 1.65403262"></polygon>
<polygon id="Fill-721" fill="#108FAB" points="2.03787077 2.88555877 2.38180923 1.64851262 2.43984 1.65417415 2.09590154 2.88980492"></polygon>
<polygon id="Fill-723" fill="#108CA7" points="2.32321231 1.64426646 2.38124308 1.64851262 2.03730462 2.88555877 1.97927385 2.88131262"></polygon>
<path d="M1.93341538,2.877208 L2.27876923,1.63166954 L2.28301538,1.63166954 C2.28584615,1.63166954 2.28726154,1.63308492 2.29009231,1.63308492 L2.32264615,1.644408 L1.98012308,2.88145415 L1.93341538,2.877208 Z" id="Fill-725" fill="#1089A3"></path>
<path d="M2.23347692,1.62629108 C2.24904615,1.62770646 2.2632,1.62912185 2.27876923,1.63195262 L1.93341538,2.87749108 L1.90369231,2.87466031 C1.89661538,2.87466031 1.89236923,2.87324492 1.88812308,2.87324492 L2.23347692,1.62629108 Z" id="Fill-729" fill="#0F859F"></path>
<path d="M2.23135385,1.62487569 L1.88741538,2.87324492 C1.886,2.87324492 1.88458462,2.87182954 1.88175385,2.87182954 L1.84353846,2.85767569 L2.17473846,1.62062954 L2.23135385,1.62487569 Z" id="Fill-731" fill="#0F819B"></path>
<polygon id="Fill-733" fill="#0E7E97" points="1.78621538 2.85371262 2.12873846 1.61808185 2.17544615 1.62091262 1.84424615 2.85795877"></polygon>
<path d="M1.74064,2.84819262 L2.08599385,1.60265415 L2.12845538,1.61822338 L1.78593231,2.85385415 L1.76045538,2.85243877 C1.75620923,2.85102338 1.75196308,2.85102338 1.74771692,2.849608 C1.74488615,2.849608 1.74205538,2.84819262 1.74064,2.84819262" id="Fill-735" fill="#0E7B92"></path>
<polygon id="Fill-737" fill="#0D778E" points="1.69648 2.83432185 2.03900308 1.59869108 2.08571077 1.60293723 1.74035692 2.84847569 1.72195692 2.84422954"></polygon>
<path d="M1.99569231,1.58340492 L2.03956923,1.59897415 L1.69704615,2.83460492 L1.67156923,2.83318954 C1.66449231,2.83177415 1.65741538,2.83035877 1.65033846,2.82894338 L1.99569231,1.58340492 Z" id="Fill-739" fill="#0D7389"></path>
<path d="M1.92449846,1.56542954 C1.93299077,1.56826031 1.94148308,1.57109108 1.95139077,1.57250646 L1.60603692,2.81662954 L1.56357538,2.80106031 L1.90609846,1.56401415 L1.92449846,1.56542954 Z" id="Fill-741" fill="#0C6D81"></path>
<polygon id="Fill-743" fill="#0B697D" points="1.51955692 2.78591569 1.86208 1.54886954 1.90595692 1.56443877 1.56343385 2.80148492"></polygon>
<path d="M1.81876923,1.53372492 C1.82018462,1.53514031 1.8216,1.53514031 1.82301538,1.53655569 C1.83009231,1.53797108 1.83716923,1.54080185 1.84283077,1.54221723 L1.86264615,1.54929415 L1.52012308,2.78634031 L1.47624615,2.77077108 L1.81876923,1.53372492 Z" id="Fill-745" fill="#0B6579"></path>
<path d="M1.43236923,2.75562646 L1.77489231,1.51858031 C1.78621538,1.52282646 1.79753846,1.52707262 1.81027692,1.53131877 C1.81310769,1.53273415 1.81593846,1.53414954 1.81876923,1.53414954 L1.47624615,2.77119569 L1.43236923,2.75562646 Z" id="Fill-747" fill="#0B6275"></path>
<path d="M1.72124923,1.49635877 C1.73823385,1.50343569 1.75663385,1.511928 1.77503385,1.51900492 L1.43251077,2.75605108 L1.40420308,2.74755877 C1.39995692,2.744728 1.39571077,2.74331262 1.39146462,2.74048185 C1.38721846,2.73906646 1.38155692,2.73623569 1.37872615,2.73482031 L1.72124923,1.49635877 Z" id="Fill-749" fill="#0B5F71"></path>
<path d="M1.72124923,1.49635877 L1.37872615,2.73482031 C1.36315692,2.726328 1.34900308,2.71925108 1.33626462,2.71075877 L1.20746462,2.55931262 L1.55423385,1.31094338 L1.55848,1.31660492 C1.54574154,1.364728 1.58395692,1.419928 1.67878769,1.475128 C1.69152615,1.48220492 1.70709538,1.48928185 1.72124923,1.49635877" id="Fill-755" fill="#0A5B6D"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="33px" height="35px" viewBox="0 0 33 35" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>路由器</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#0042BE" offset="0%"></stop>
<stop stop-color="#0073FC" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="13.8738739" width="32.4774775" height="21.1261261" rx="2.52252252"></rect>
<linearGradient x1="100%" y1="56.8067642%" x2="0%" y2="40.3552058%" id="linearGradient-3">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<rect id="path-4" x="0" y="11.036036" width="32.4774775" height="21.1261261" rx="2.52252252"></rect>
<linearGradient x1="54.9387755%" y1="66.0866477%" x2="45.0612245%" y2="27.2061435%" id="linearGradient-5">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-162.350446%" y1="50%" x2="100%" y2="50%" id="linearGradient-6">
<stop stop-color="#FFFFFF" offset="0%"></stop>
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="48.3262804%" y1="34.4238281%" x2="50%" y2="79.7851562%" id="linearGradient-7">
<stop stop-color="#0054D5" offset="0%"></stop>
<stop stop-color="#2A92EE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="0%" y1="50%" x2="266.454381%" y2="50%" id="linearGradient-8">
<stop stop-color="#0054D5" offset="0%"></stop>
<stop stop-color="#2A92EE" offset="100%"></stop>
</linearGradient>
</defs>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="4网络构建与联通V2.0" transform="translate(-22.000000, -699.000000)">
<g id="路由器" transform="translate(22.000000, 699.000000)">
<g id="矩形">
<use fill="#454343" xlink:href="#path-2"></use>
<use fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
</g>
<g id="矩形">
<use fill="#5D5959" xlink:href="#path-4"></use>
<use fill="url(#linearGradient-3)" xlink:href="#path-4"></use>
</g>
<path d="M6.77927928,0 C7.7370704,-1.75943374e-16 8.51351351,0.776443114 8.51351351,1.73423423 L8.51351351,11.036036 L8.51351351,11.036036 L5.04504505,11.036036 L5.04504505,1.73423423 C5.04504505,0.776443114 5.82148816,1.75943374e-16 6.77927928,0 Z" id="矩形" fill="url(#linearGradient-5)"></path>
<path d="M6.14864865,1.26126126 C6.58400825,1.26126126 6.93693694,1.61418995 6.93693694,2.04954955 L6.93693694,11.036036 L6.93693694,11.036036 L5.36036036,11.036036 L5.36036036,2.04954955 C5.36036036,1.61418995 5.71328905,1.26126126 6.14864865,1.26126126 Z" id="矩形" fill="url(#linearGradient-6)"></path>
<path d="M26.3288288,0 C27.2866199,-1.75943374e-16 28.0630631,0.776443114 28.0630631,1.73423423 L28.0630631,11.036036 L28.0630631,11.036036 L24.5945946,11.036036 L24.5945946,1.73423423 C24.5945946,0.776443114 25.3710377,1.75943374e-16 26.3288288,0 Z" id="矩形" fill="url(#linearGradient-5)"></path>
<path d="M25.6981982,1.26126126 C26.1335578,1.26126126 26.4864865,1.61418995 26.4864865,2.04954955 L26.4864865,11.036036 L26.4864865,11.036036 L24.9099099,11.036036 L24.9099099,2.04954955 C24.9099099,1.61418995 25.2628386,1.26126126 25.6981982,1.26126126 Z" id="矩形" fill="url(#linearGradient-6)"></path>
<g id="编组-7" transform="translate(6.306306, 12.927928)">
<rect id="矩形" fill="url(#linearGradient-7)" x="0" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="2.52252252" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="5.36036036" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="7.88288288" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="10.7207207" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="13.2432432" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="16.0810811" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-8)" x="18.6036036" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
</g>
<ellipse id="椭圆形" fill="#18D6FF" cx="8.1981982" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<ellipse id="椭圆形" fill="#18D6FF" cx="13.5585586" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<ellipse id="椭圆形" fill="#18D6FF" cx="18.9189189" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<ellipse id="椭圆形" fill="#18D6FF" cx="23.963964" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<g id="编组" transform="translate(12.297297, 21.441441)" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.26126126">
<polyline id="路径-45" points="0 0 2.43243243 0 5.67567568 5.67567568 8.10810811 5.67567568"></polyline>
<polyline id="路径-45" transform="translate(4.054054, 2.837838) scale(-1, 1) translate(-4.054054, -2.837838) " points="0 0 2.43243243 0 5.67567568 5.67567568 8.10810811 5.67567568"></polyline>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

@ -0,0 +1,26 @@
### 在计算机网络中,路由器、交换机、集线器和主机是网络中常见的设备,它们之间扮演不同的角色,并负责网络通信的不同方面。
- 路由器SimRouter路由器是一个网络设备用于在不同网络之间进行数据包转发。它通过查看数据包的目标地址并根据网络中的路由表来确定最佳路径将数据包从源地址发送到目标地址。路由器负责跨越不同的网络如互联网将数据包从一个网络转发到另一个网络。
- 交换机SimSwitch交换机是一个用于连接多个设备的网络设备。它在局域网LAN中起到数据包转发和交换的作用。当一个数据包从一个端口进入交换机时交换机会检查数据包的目标MAC地址并将其转发到相应的目标端口以便将数据包传递给正确的目标设备。交换机通过建立MAC地址表来维护设备的连接关系以便快速转发数据包。
- 集线器SimHub集线器是一种被动的网络设备用于将多个设备连接在一起形成局域网LAN。当一个数据包到达集线器时它会被广播到所有连接的设备无论数据包的目标地址是什么。这会导致网络中的所有设备都会接收到数据包但只有目标设备会处理该数据包。因此集线器的性能较低并且在现代网络中很少使用。
- 主机SimHost主机是指连接到网络的计算机或其他设备。主机可以是个人电脑、服务器、移动设备等。主机可以通过路由器、交换机或集线器与其他设备进行通信。在网络中主机可以发送和接收数据包可以是数据的源或目标。
### 关于它们之间的通信方式:
- 路由器在不同网络之间进行通信通过查找路由表将数据包从一个网络转发到另一个网络。它使用IP地址来寻址和路由数据包。
交换机在局域网中进行通信它根据目标设备的MAC地址将数据包转发到正确的端口。交换机在数据链路层操作使用MAC地址来寻址数据包。
集线器将所有连接的设备广播到网络中,所有设备都可以接收到发送到网络的数据包。这种广播方式会导致网络中的所有设备都能看到数据包,但只有目标设备会处理它。
主机可以直接连接到交换机或集线器并通过它们进行通信。主机使用IP地址和MAC地址来寻址和识别数据
#### 补充
1. TCP/IP协议栈TCP/IP协议栈是互联网通信所使用的基本协议集合。它由多个协议组成其中最常用的是TCP传输控制协议和IP互联网协议。TCP负责可靠的数据传输而IP则负责将数据包从源主机传送到目标主机。
2. 以太网以太网是一种局域网技术用于在局域网内传输数据。它使用物理介质如电缆来连接多台计算机和网络设备。以太网使用MAC地址媒体访问控制地址来唯一标识每个网络接口。
3. IP地址分配IP地址是在互联网中用于标识网络设备的唯一地址。IP地址分为IPv4和IPv6两个版本。IPv4由32位二进制数组成通常以点分十进制表示例如192.168.0.1。IPv6由128位二进制数组成以冒号分隔的八组十六进制数表示。
4. MAC地址表MAC地址表是交换机使用的表格记录了与交换机连接的设备的MAC地址和对应的接口。当交换机接收到一个数据帧时它会查找目标MAC地址并将数据帧只发送到目标设备所连接的接口而不是广播到所有接口上。
5. 路由表路由器使用路由表来确定数据包的最佳路径。路由表中包含了目的网络的IP地址范围和下一跳的路由器的IP地址。路由器将数据包转发到适当的下一跳路由器直到达到目标网络。
6. 集线器:集线器是一种物理层设备,用于将多个以太网设备连接在一起。当集线器接收到一个数据帧时,它会将数据帧广播到所有连接的设备,这种广播方式会导致网络拥塞和冲突。
7. 交换机交换机是一种数据链路层设备用于连接多个以太网设备并根据MAC地址表将数据帧只发送到目标设备所连接的接口。交换机提供了更高的带宽和更低的延迟因为它只将数据发送到目标设备而不是广播。
8. 路由器:路由器是一种网络层设备,用于在不同的网络之间转发数据包。路由器使用路由表决定数据包的下一个跳,并负责在网络之间转发数据。路由器能够实现不同网络之间的互联和广域网的连接。

Binary file not shown.
Loading…
Cancel
Save