为什么python子进程stdin.write()在stdin.flush()之后不起作用



gameserver.py

import config
import os
from subprocess import Popen, PIPE, STDOUT

class GameserverHandler:
def __init__(self):
print("==== Gameserver ====")
self.__gameServerInstance__ = self.restart_gameserver()
print("tGameserver started")
def restart_gameserver(self):
if os.path.exists(config.bot_config[0]['GameServer']['OutPutFile']):
os.remove(config.bot_config[0]['GameServer']['OutPutFile'])
f = open(config.bot_config[0]['GameServer']['OutPutFile'], "wb")
return Popen(config.bot_config[0]['GameServer']['Path'], stdin=PIPE, stdout=f, stderr=STDOUT)
def send_command(self, command):
try:
self.__gameServerInstance__.stdin.write(str.encode(command))
self.__gameServerInstance__.stdin.flush()
except BrokenPipeError:
pass
except OSError as e:
exit()

主.py

import config
import gameserver

gameServer = gameserver.GameserverHandler()
a = input()
gameServer.send_command('quitn')

大家好,我刚刚写了我的第一个python脚本。这个脚本只是在我的计算机上启动一个游戏服务器,在一个文件中写入stdout和stderr,并为我提供向服务器发送命令的选项。

但是有一个问题,当我使用send_command((时,游戏服务器不会得到stdin.write。我读到我必须在它后面放一个flush((。但这没有帮助。有趣的是,当我把代码改成这样时:

def send_command(self, command):
try:
self.__gameServerInstance__.stdin.write(str.encode(command))
self.__gameServerInstance__.stdin.flush()
self.__gameServerInstance__.stdout.flush()
self.__gameServerInstance__.stderr.flush()
except BrokenPipeError:
pass
except OSError as e:
exit() 

我收到这个错误

Traceback (most recent call last):   File "D:ProjektepythonPycharmProjectsServerLaunchermain.py", line 7, in <module>
gameServer.send_command('quit')   File "D:ProjektepythonPycharmProjectsServerLaunchergameserver.py", line 22, in send_command
self.__gameServerInstance__.stdout.flush() AttributeError: 'NoneType' object has no attribute 'flush'

我认为这是因为我将stdout、stderr设置为一个文件,但为什么它比。

抱歉问了一个可能很愚蠢的问题,我刚刚开始python编程

Serge Ballesta回答后更新

更改了代码:gameserver.py

def restart_gameserver(self):
if os.path.exists(config.bot_config[0]['GameServer']['OutPutFile']):
os.remove(config.bot_config[0]['GameServer']['OutPutFile'])
f = open(config.bot_config[0]['GameServer']['OutPutFile'], "wb")
return Popen(config.bot_config[0]['GameServer']['Path'], stdin=PIPE, stdout=f, stderr=STDOUT)

主.py

import config
import gameserver
import discord
gameServer = gameserver.GameserverHandler()
a = input()
print("SENDING")
gameServer.send_command('quitn')
print("FINISH")
a = input()

更改:

  • stderr到子进程。标准输出
  • 将文件操作更改为"wb">
  • 在send_command中添加新行

但是的,不知道为什么,但这个过程仍然没有得到退出。当我把所有东西都放在main.py中并删除类时,就像这样。

if os.path.exists(config.bot_config[0]['GameServer']['OutPutFile']):
os.remove(config.bot_config[0]['GameServer']['OutPutFile'])
f = open(config.bot_config[0]['GameServer']['OutPutFile'], "wb")
p = Popen(config.bot_config[0]['GameServer']['Path'], stdin=PIPE, stdout=f, stderr=STDOUT)
a = input()
p.stdin.write(b'quit')

它起作用了,我不知道为什么,可能是stdin没有刷新吗?

以及快速答案的thx@Serge Ballesta

您的代码中存在许多不一致之处:

  1. 您对stdout和stderr使用相同的文件。这是错误的,可能会导致文件中的输出不正确。您应该使用特殊值subprocess.STDOUT:

    from subprocess import Popen, PIPE, STDOUT
    ...
    return Popen(config.bot_config[0]['GameServer']['Path'], stdin=PIPE,
    stdout=f, stderr=STDOUT)
    
  2. 您使用字节IO定义子进程,但以文本形式打开输出文件。您应该使用二进制模式:

    f = open(config.bot_config[0]['GameServer']['OutPutFile'], "wb")
    
  3. 您发送一个命令quit。大多数CLI程序都希望命令以换行符终止。您应该在命令中添加一个n

    self.__gameServerInstance__.stdin.write(str.encode(command) + 'bn')
    

    gameServer.send_command('quitn')
    

在这些修复之后,我可以成功地启动cmd.exe子进程(在Windows上(,在exitn命令之后终止它,并在输出文件中获得预期的数据。