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

Windows上具有恒定输出的Python无块子访问输入

  •  0
  • ddaniels  · 技术社区  · 11 年前

    我正在尝试使用subaccess和_thread模块运行命令。子访问有一个输出流。为了解决这个问题,我使用了两个线程,一个不断打印新行,另一个检查输入。当我传递子访问输入时 proc.stdin.write('Some string') 它返回1,然后没有输出。根据我读过的大多数其他问题,沟通并不奏效,因为它阻止了等待EOF,尽管它确实打印了要返回的内容的第一行。我看到了一些使用“pty”的解决方案,但它在Windows上不受支持。

    如果您想自己尝试,服务器文件夹中的文件只是一个minecraft服务器。

    from subprocess import Popen,PIPE
    import _thread
    import sys
    # asdf
    proc = None
    run = True
    stdout = None
    stdin = None
    
    
    def getInput():
        global proc
        global run, stdin, stdout
        print("Proc inside the get input funct"+str(proc))
        inputs = input("Enter Something" + "\n")
        print("YOU ENTERED:", inputs)
        print("ATTEMPTING TO PIPE IT INTO THE CMD")
        run = True
    
        """----------------------------------------"""
        """        Works but blocks outputs        """
        """----------------------------------------"""
        # out,err=proc.communicate(bytes(inputs,'UTF-8'))
        # proc.stdin.flush()
        # print("Out is: "+out)
    
    
    
    
        """----------------------------------------"""
        """   Doesn't write but doesn't block      """
        """----------------------------------------"""
        # test = 0
        # test=proc.stdin.write(bytes(inputs,'UTF-8'))
        # print(test)
        # proc.stdin.flush()
    
    
    def execute(command):
        global proc, stdin, stdout
        proc = Popen(command, cwd='C://Users//Derek//Desktop//server//',stdin=PIPE,stdout=PIPE,stderr=stdout, shell=True)
        lines_iterator = iter(proc.stdout.readline, "")
        print("Proc inside of the execute funct:"+str(proc))
        # print(lines_iterator)
        for line in lines_iterator:
            # print(str(line[2:-1]))
            # if line.decode('UTF-8') != '':
            print(line[:-2].decode('UTF-8')),  # yield line
            sys.stdout.flush()
    
    
    threadTwo = _thread.start_new_thread(execute, (["java", "-jar", "minecraft_server.jar"], ))
    
    while 1:
        if run and proc!=None:
            run = False
            threadOne = _thread.start_new_thread(getInput, ( ))
    
        pass
    
    1 回复  |  直到 11 年前
        1
  •  1
  •   jfs    11 年前

    proc.communicate() 等待子流程完成,因此最多可以使用它 一旦 你可以通过 全部的 立即输入,并在子进程退出后获取所有输出。

    如果不修改输入/输出,则不需要重定向子进程的stdin/stdout。

    要将输入馈送到后台线程中的子进程,并在其逐行到达时立即打印其输出,请执行以下操作:

    #!/usr/bin/env python3
    import errno
    from io import TextIOWrapper
    from subprocess import Popen, PIPE
    from threading import Thread
    
    def feed(pipe):
        while True:
            try: # get input
                line = input('Enter input for minecraft')
            except EOFError:
                break # no more input
            else:
                # ... do something with `line` here
    
                # feed input to pipe
                try:
                    print(line, file=pipe)
                except BrokenPipeError:
                    break # can't write to pipe anymore
                except OSError as e:
                    if e.errno == errno.EINVAL:
                        break  # same as EPIPE on Windows
                    else:
                        raise # allow the error to propagate
    
        try:
            pipe.close() # inform subprocess -- no more input
        except OSError:
            pass # ignore
    
    with Popen(["java", "-jar", "minecraft_server.jar"],
               cwd=r'C:\Users\Derek\Desktop\server',
               stdin=PIPE, stdout=PIPE, bufsize=1) as p, \
         TextIOWrapper(p.stdin, encoding='utf-8', 
                       write_through=True, line_buffering=True) as text_input:
        Thread(target=feed, args=[text_input], daemon=True).start()
        for line in TextIOWrapper(p.stdout, encoding='utf-8'):
            # ... do something with `line` here
            print(line, end='')
    

    关于的说明 p.stdin :

    1. print() 在每个 line 。这是必要的,因为 input() 去掉换行符
    2. p.stdin.flush() 在每行之后调用( line_buffering=True )

    minecraft的输出可能会延迟,直到其标准输出缓冲区被刷新。

    如果您对 “做点什么 线 此处“ 注释不会重定向相应的管道(暂时忽略字符编码问题)。

    TextIOWrapper 默认情况下使用通用换行模式。具体说明 newline 如果您不希望,请显式指定参数。