本文已参与「新人创作礼」活动,一起敞开创作之路。

多线程/进程问题:以iperf3为例

在给一个项目写可视化的时候,项目需要用iperf3来进行网络测验。

Github源码 ipef3分为服务器server端和客户client端两个进程,一般运用cmd翻开,敞开测验的界面是这个姿态:

server端

python多线程/进程问题:以iperf3为例与测试平台解析

client端:

python多线程/进程问题:以iperf3为例与测试平台解析

第一个坑

为了能够运用python代码操控操控台翻开iperf3.exe,运用==subprocess==模块来发动。

可是subprocess直接发动程序,需要将iperf3.exe的路径加入到体系变量里,这样就不需要cmd进入对应文件目录再发动:

python多线程/进程问题:以iperf3为例与测试平台解析

第二个坑

在解决直接用指令翻开ipef3.exe之后,就是用subprocess运用iperf3.exe -siperf3.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调试界面竟然没有退出!!

python多线程/进程问题:以iperf3为例与测试平台解析

后来细心想想,我是调用了个线程敞开了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。简单粗犷又好用:

python多线程/进程问题:以iperf3为例与测试平台解析

感谢:雷学长

测验渠道代码解析

文件结构

  • 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: