代码之家  ›  专栏  ›  技术社区  ›  johnashu

在发出ctrl+c命令之前弹出读取数据

  •  1
  • johnashu  · 技术社区  · 8 年前

    我有一个用c语言编写的windows命令行工具,它通过串行usb加密狗扫描蓝牙设备。

    它将循环遍历范围内的所有设备,直到收到ctrl+c命令为止。

    device1 name firmware
    device2 name firmware
    device3 name firmware
    device1 name firmware
    device2 name firmware
    device3 name firmware
    ...
    

    我想在扫描到达某个设备时停止扫描,这样我就可以发出更新固件命令。

    此时,我只能捕获Ctrl +C命令后的输出,使用以下函数启动扫描、休眠,然后发出CTRL+C命令,然后捕获错误并处理输出 except 阻止:

            command = [self.cli_tool, '-s']
    
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            startupinfo.wShowWindow = subprocess.SW_HIDE
    
            stream = []
    
            if self.check_dongle_firmware() is not False:
                try:                    
                    self.proc = subprocess.Popen(
                                command, 
                                stdin=subprocess.PIPE, 
                                stdout=subprocess.PIPE, 
                                stderr=subprocess.DEVNULL, 
                                startupinfo=startupinfo)
    
                    time.sleep(SCAN_TIMEOUT)
                    os.kill(self.proc.pid, signal.CTRL_C_EVENT)
                    self.proc.wait()
    
                except KeyboardInterrupt:                
                    for line in self.proc.stdout:
                        stream.append(line)                         
    
                    for x in stream[7:]:
                        x = x.decode()
                        print(x.strip())   
    

    我想要这样的东西:

    stream = []
    
     self.proc = subprocess.Popen(
                                command, stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE, 
                                stderr=subprocess.DEVNULL, 
                                startupinfo=startupinfo)
    
    for line in self.proc.stdout:
        stream.append(line) 
        if 'device2' in line.decode().split():
            os.kill(self.proc.pid, signal.CTRL_C_EVENT)
            self.proc.wait()
    

    但这不起作用。它不会一次读取1行,并且永远不会达到CTRL+C事件。

    我需要一次读取和处理1行,这样我就可以停止在某个设备上的进程。

    目前,它只读取空字节或字符串,具体取决于管道属性。

    打印到屏幕(带有启动信息关闭)或保存到文件而不发布CTRL+C将呈现空。 我尝试了各种组合使用:

    universal_newlines=True

    bufsize=1

    self.proc.communicate()[0]

    当我使用类似于 ping 我没有问题,完全控制了输出。

    我试过类似的东西,但没有什么能满足我的需要。

    我想我遗漏了一些显而易见的东西,或者是由于工具没有在C代码中应用flush命令而无法实现?

    任何指导或建议都是值得赞赏的!

    在c代码中,fflush只出现在我认为是用于错误处理的以下位置。

    project.h 两者都有 bootloader\src\common\ receiver\src\common\

    //*************************************************************************
    //------------------------- assertion of errors  --------------------------
    //*************************************************************************
    /*
     *   The format is assert(eval, error);
     *
     *   If 'eval' equals 0 then there is an error printed with number 'error'.
     *
     */
    
    #define ERR_STACKOVERFLOW 0   // Out of stack space
    #define ERR_SCH_OVERFLOW  1   // Scheduler overflow
    #define ERR_SCH_OUTRANGE  2   // Scheduler out of range
    #define ERR_WSHRS_OUTRANGE  3   // Scheduler out of range
    
    #ifdef __nDEBUG__
    
    #include "./error/error.h"
    ....
    #include <stdio.h>
    #define DBG_PRINT(a, args...) { printf(a, ##args);fflush(stdout); }
    
    1 回复  |  直到 8 年前
        1
  •  3
  •   johnashu    8 年前

    这里的问题可能是,cli程序的输出是块缓冲的,因为输出文件描述符与终端没有关联。您声称,它使用“ping”而不是cli程序,因此它肯定是子进程本身的问题。

    由于是您自己编写的cli程序,请确保它不会缓冲输出(即 fflush() 每行打印后。

    具体来说,调整代码如下所示:

    while (somecondition) {
        ...
        printf("%s %s %s\n", device, name, firmware);
        fflush(stdout); // <- Add this line after the printf
        ...
    }
    

    或者,正如melpomene建议的那样,您也可以在程序的早期将stdout切换为行缓冲:

    setvbuf(stdout, NULL, _IOLBF, 0);
    

    Online C11 standard ,7.21.3/3页:

    当一条小溪 无缓冲 字符的目的是从源或目的地尽快出现。否则,字符可以作为块累积并作为块从主机环境传输到主机环境。当一条小溪 完全缓冲 ,当缓冲区填满时,字符将作为块传输到主机环境或从主机环境传输。当一条小溪 行缓冲 ,当遇到新行字符时,字符将作为块传输到主机环境或从主机环境传输。此外,当缓冲区被填满、在无缓冲流上请求输入、或在需要从主机环境传输字符的行缓冲流上请求输入时,字符打算作为块传输到主机环境。对这些特性的支持是由实现定义的,并且可能通过 setbuf setvbuf 功能。

    7.21.3/7条:

    在程序启动时,预定义了三个文本流,不需要显式打开。 标准输入 (用于读取常规输入) 标准输出 (用于写入常规输出),以及 标准误差 (用于写入诊断输出)。当最初打开时,标准错误流没有完全缓冲;当且仅当可以确定流不是指交互设备时,标准输入流和标准输出流才完全缓冲。