Github源码
ipef3分为服务器server端和客户client端两个进程,一般使用cmd打开,开启测试的界面是这个样子:
为了能够使用python代码控制控制台打开iperf3.exe,使用subprocess模块来启动。
但是subprocess直接启动程序,需要将iperf3.exe的路径加入到系统变量里,这样就不需要cmd进入对应文件目录再启动:
在解决直接用命令打开ipef3.exe之后,就是用subprocess使用iperf3.exe -s
和iperf3.exe -c 127.0.0.1
这两个命令,应该这样写:
def server():
with subprocess.Popen(["iperf3.exe", "-s"], stdout=subprocess.PIPE, universal_newlines=True) as process:
while True:
print("doing")
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
# with open('D:\ForStudy\python练习\练习\项目\out.txt', 'w+') as file:
# sys.stdout = file
# print(output.strip())
# sys.stdout = stdout#结果重定向到文档
a=output.strip()
rc = process.poll()
注意subprocess.Popen(["iperf3.exe", "-s"],
只有这样写,才是正确的输入参数的格式,将-s这个参数和前面分开!!!!!
虽然我现在能够启动server和client并且实现了iperf推流,但是在这两个线程退出之后,我的vscode调试界面居然没有退出!!
后来仔细想想,我是调用了个线程开启了iperf这个进程,因此虽然这次推流结束了但是iperf server服务进程还在,因此我还需要将这个进程退出才行:
if flag ==1:
print("client has shut")
with subprocess.Popen("taskkill /IM iperf3.exe /F", stdout=subprocess.PIPE, shell=True,universal_newlines=True) as process:
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
print(output.strip())
这样,我就输入cmd命令将进程关闭了hhhh。简单粗暴又好用:
感谢:雷学长
product.py 主界面
items.py Node类(三节点组网时每个节点的信息) API_need类(所需的函数) Button 类(按钮的属性)
Remote.py
UDP_test.py
UDPPingerClient.py
2-2-UDPPingServer.py
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8uJ3P16O-1621152582353)(C:\Users\Administrator\Desktop\QQ图片20210114230810.png)]
product.py 77行
if条件内为判断点击到了“V段测试”
if(点击到了“V段测试”)
print("click 1")
BK_flag=2#第二个页面
S_flag=0
Ceshi_1.if_click = 1#按钮变灰
Ceshi_2.if_click = 0
Ceshi_3.if_click=0
点击选择到V段之后,会点击测试客户端/测试服务器,下面以点击到服务器为例102行
if(测试服务器)
print("click 4")
node2.if_click = 1
node3.if_click = 0
Ceshi_4.if_click = 1
Ceshi_5.if_click = 0
Ceshi_6.if_click = 0
V_waiting_flag=1#显示等待回复
if S_flag==0:#判断这是V段而不是S段
#监听回复报文
V_listen=Thread(target=api.V_config_server_receive, args=(api,))
V_listen.start()
print('V is listening')
#发送配置报文
time.sleep(1)
V_send=Thread(target=api.V_config_server_send, args=(api,))
V_send.start()
这段代码做了两件事,V_listen线程监听了25600端口,准备接受板子配置好之后返还的UDP报文;随后等待2s,V_send向25600端口发送配置报文:
看看V_send线程启的函数:
def V_config_server_send(self):
# port=11000
port=25600
text2=b'给节点2发送的配置报文内容'
text3=b'给节点3发送的配置报文内容'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(text2, ('192.168.3.2', port))
sock.sendto(text3,('192.168.3.3',port))
print("已发送")
再看看V_listen线程启的函数:
def V_config_server_receive(self):
port=11000
port=25600
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', port))
data, address = sock.recvfrom(1024)
time.sleep(2)
self.V_num=1
self.V_if_iperf=1
# print(data)
self.V_iperf_server(self)
注意在sock.recvfrom(1024)函数之后,即收到了板子回复报文之后,执行了**self.V_iperf_server(self)**函数,这是在配置好了之后,开启iperf的server端。
看看这个V_iperf_server函数:
def V_iperf_server(self):
fontObj = pygame.font.Font(self.ttf_abs, 17)
if 'Windows'in platform.platform():#Windows系统
print('This platform is Windows')
with subprocess.Popen(["iperf-2.1.0-rc-win.exe","-s","-u","--port","24600","-i","2"], shell=True,stdout=subprocess.PIPE, universal_newlines=True) as process:
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
self.render.append(fontObj.render(output.strip(), False, (0, 0, 0)))
if len(self.render)>6:#实现滚动
del self.render[0]
iperf server端在接收到iperf的信息之后,暂存为output,然后转化成字体格式保存在self.render列表中
(iperf 的client端原理一样,不用赘述)
95行,点击到“三节点组网”,BK_flag=3,第三个界面
46行,开局就打开监听
server = Thread(target=remote.pipe_begin, args=(remote,))
server.start()
执行Remote.py中的remote类中的pipe_begin函数:
def pipe_begin(self):#建立pipe
parent_conn, child_conn=Pipe()
fa= multiprocessing.Process(target=self.UDP_test_server, kwargs={'self':self,'pipe':child_conn})#开启管道的发端,为UDP_test_server函数,管道的接收端就默认为自己了
fa.start()
flag=1
while True:
temp = parent_conn.recv()
temp=temp.split()
# print('receive data is:',temp)
if flag==1:
self.Pitch_angle = temp[0]
self.Yaw_angle=temp[1]
self.Roll_angle = temp[2]
#省略下面的部分代码
#现在邻接表的选择也由S状态决定
if self.s_node1=='1' and self.s_node2=='1':
self.Nighbour_v["12"]=1
self.Nighbour_s["12"]=1
if self.s_node1=='1' and self.s_node3=='1':
self.Nighbour_v["13"]=1
self.Nighbour_s["13"]=1
if self.s_node3=='1' and self.s_node2=='1':
self.Nighbour_v["23"]=1
self.Nighbour_s["23"]=1
flag+=1
elif flag==2:
flag+=1
elif flag==3:
flag==1#隔2个报文收一个,避免发的速率过快处理不来
UDP_test_server函数是执行了UDP_test.py文件中的server函数,
UDP_test.py中 的server函数:
def server(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', port))
while True:
data, address = sock.recvfrom(1024)
# print(data)
node_data(data)#执行报文解析函数
node_data()#报文解析函数就是将报文中的各字段解析出来,然后print出来那些数据:
print(Pitch_angle_s, Yaw_angle_s, Roll_angle_s,
Node_x_s, Node_y_s, Node_z_s, Node_x_speed_s, Node_y_speed_s, Node_z_speed_s, Node1_id,
Node2_x_s, Node2_y_s, Node2_z_s, Node2_x_speed_s, Node2_y_speed_s, Node2_z_speed_s, Node2_id,
Node3_x_s, Node3_y_s, Node3_z_s, Node3_x_speed_s, Node3_y_speed_s, Node3_z_speed_s, Node3_id,
now_node,s_info['node1']['id'],s_info['node2']['id'],s_info['node3']['id'])
这些数据被print到了管道里,被Remote.py中的pipe_begin()函数接受并保存到self中的变量里
主要讲190行之后的内容:
if api.render != []:
# print(api.render)
loding_flag=0
for i in range(len(api.render)):
screen.blit(api.render[i], (460, 470 + 23 * i))
elif loding_flag==1:
font_loding = pygame.font.Font(api.ttf_abs, 30)
text_big1 = font.render("配置中", 1, (255, 10, 10))
screen.blit(text_big1,(700,500))
这是判断是否在配置中,如果配置结束了,开始iperf了,那么api.render变量中就会保存iperf的信息,然后就会依次显示出来:screen.blit(api.render[i], (460, 470 + 23 * i))
222行,在发送配置UDP报文,但是还没有收到板子的回复时,显示“等待回复中”字样
if len(api.render)>=3:
V_waiting_flag=0
elif V_waiting_flag==1:
pygame.draw.rect(screen,[200,200,200],[570,220,250,120],0)
font_loding = pygame.font.Font(api.ttf_abs, 30)
text_big1 = font.render("等待回复中", 1, (0, 0, 0))
screen.blit(text_big1,(600,250))
242行到258行是根据节点的信息,判断节点该不该点亮,255行则是在修改邻接矩阵,决定后面的连线情况
261行 为画出连线
380到388行,为显示那几个大字
390行 为刷新屏幕,因为pygame的逻辑,这是一个整个的大循环,每个循环之后都需要刷新一遍元素,重新显示
391行可以看作是屏幕刷新率
学长加油