简体   繁体   中英

Why did python subprocess stdin.write() not work after a 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()

main.py

import config
import gameserver


gameServer = gameserver.GameserverHandler()
a = input()
gameServer.send_command('quit\n')

Hallo everyone, i just wrote my first python script. This script just starts a gameserver on my computer, write the stdout and stderr in a file and gives me an option to send commands to the server.

But there is the Problem when i use send_command() the gameserver dont gets the stdin.write. I read that i have to put a flush() after it. But this is not helping. Funny is when i change the code to this:

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() 

I get this Error

Traceback (most recent call last):   File "D:\Projekte\python\PycharmProjects\ServerLauncher\main.py", line 7, in <module>
    gameServer.send_command('quit')   File "D:\Projekte\python\PycharmProjects\ServerLauncher\gameserver.py", line 22, in send_command
    self.__gameServerInstance__.stdout.flush() AttributeError: 'NoneType' object has no attribute 'flush'

I think its because i set the stdout, stderr to a file, but why is it working than.

Sorry for a maybe dumb question, i'm just started python programming

UPDATE AFTER ANSWER from Serge Ballesta

Changed the code: 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)

main.py

import config
import gameserver
import discord

gameServer = gameserver.GameserverHandler()
a = input()
print("SENDING")
gameServer.send_command('quit\n')
print("FINISH")
a = input()

Changes:

  • stderr to subprocess.STDOUT
  • change the file operation to 'wb'
  • add a new line to the send_command

But yeah dont know why but still the process dont get the quit. When i put everything in the main.py and remove the class and so like this.

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')

it works, i dont know why, could it be that the stdin is not flushing?

And thx for the fast answer @Serge Ballesta

There are a number of inconsistencies in your code:

  1. you use the same file for both stdout and stderr. That is wrong and may lead to incorrect output in the file. You should use the special value subprocess.STDOUT :

     from subprocess import Popen, PIPE, STDOUT... return Popen(config.bot_config[0]['GameServer']['Path'], stdin=PIPE, stdout=f, stderr=STDOUT)
  2. You define the child process with bytes IO, yet open the output file as text. You should use binary mode:

     f = open(config.bot_config[0]['GameServer']['OutPutFile'], "wb")
  3. You send a command quit . Most CLI programs expect a command to be terminated with a newline character. You should add a \n to your command:

     self.__gameServerInstance__.stdin.write(str.encode(command) + 'b\n')

    or

     gameServer.send_command('quit\n')

After those fixes, I could successfully start a cmd.exe child process (on Windows), have it to terminate after the exit\n command, and got the expected data in the output file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM