本文已参与「新人创作礼」活动,一起敞开创作之路。
多线程/进程问题:以iperf3为例
在给一个项目写可视化的时候,项目需要用iperf3来进行网络测验。
Github源码 ipef3分为服务器server端和客户client端两个进程,一般运用cmd翻开,敞开测验的界面是这个姿态:
server端:
client端:
第一个坑
为了能够运用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
-
V段组网测验
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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行能够看作是屏幕改写率
学长加油:smiley: