2015-02-03 4 views
0

subproccess 및 _thread 모듈을 사용하여 명령을 실행하려고합니다. 하위 프로세스에는 출력 스트림이 있습니다. 이 문제를 해결하기 위해 두 개의 스레드를 사용했습니다. 한 스레드는 끊임없이 새 행을 인쇄하고 다른 스레드는 입력을 검사합니다. proc.stdin.write('Some string')을 통해 subprocess 입력을 전달하면 1을 반환하고 출력이 표시되지 않습니다. 통신문은 내가 읽은 대부분의 다른 질문에 따라 작동하지 않습니다. 왜냐하면 반환되는 내용의 첫 줄을 인쇄하지만 EOF를 기다리는 것을 차단하기 때문입니다. 'pty'를 사용하는 몇 가지 솔루션을 보았지만 Windows에서는 지원되지 않습니다.Windows에서 상수 출력을 사용하는 파이썬 블럭없는 서브 프로세스 입력

서버 폴더에있는 파일은 직접 시도하려는 경우에만 미니 크래프트 서버입니다. 한 번에 모든 입력을 전달하고 자식 프로세스가 종료 한 후 모든 출력을 얻을 수 있습니다 - 서브 프로세스

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 
+0

'_thread' 모듈을 사용하지 말고 대신'threading' 모듈을 사용하십시오. – jfs

답변

1

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()는 표준 출력 버퍼를 플러시 할 때까지 마인로부터의 출력은 지연 될 수

각 라인 (line_buffering=True) 후

  • p.stdin.flush() 호출되는 개행 스트립 때문에 필요하다.

    "do something with something line"여기에 코멘트를 추가하지 않으려면 해당 파이프를 리디렉션하지 마십시오 (문자 인코딩 문제는 잠시 무시).

    TextIOWrapper은 기본적으로 범용 개행 모드를 사용합니다. 원하지 않으면 명시 적으로 newline 매개 변수를 지정하십시오.

  • +0

    완벽하게 작동합니다! TextIOWrapper는 정확히 무엇을합니까? PIPE로 전달할 의사 파일로 작동합니까? – ddaniels

    +0

    @ddaniels :'TextIOWrapper'는 utf-8을 디코딩/인코딩하고,'p.stdin'에 대한 라인 버퍼링 동작을 강제하기 위해 사용됩니다. 여기에서 보편적 인 뉴 라인 모드를 가능하게합니다. 바이너리 파일 ('bytes'로 동작하는 파일 객체)을 래핑하고 유니 코드 텍스트 ('str' 타입)를 읽고 쓸 수있게합니다. 'universal_newlines = True'를'Popen'에 건네면'TextIOWrapper'를 내부적으로 사용합니다 (로케일의 기본 인코딩을 사용합니다). – jfs

    +0

    이것은 매우 도움이됩니다, 다시 한번 감사드립니다! – ddaniels