Python:在从属模式下将命令发送到mplayer
问题内容:
我试图在奴隶模式下运行时通过管道向mplayer发送命令:
import subprocess, time
# start mplayer
song = 'mysong.mp3'
cmd = ['mplayer', '-slave', '-quiet', song]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
# send a command every 3 seconds.
# Full command reference here: http://www.mplayerhq.hu/DOCS/tech/slave.txt
while True:
print('sleep 3 seconds ...')
time.sleep(3)
cmd = 'get_meta_artist'
print('send command: {}'.format(cmd))
p.stdin.write(cmd)
output = p.communicate()[0]
print(output)
但是输出什么都没有。
我以这个问题为例。
在终端中运行相同的mplayer命令可以正常工作。我在这里想念什么?
更新:
我将cmd从“ get_meta_artist”更改为“ get_meta_artist \ n”,以便将换行符也发送到管道,但输出中仍然没有任何内容。
UPDATE2:
我将cmd更改为“ \ npause \ n”,音乐暂停了。因此,这意味着可以通过stdin发送命令。这意味着“ \ nget_meta_artist \
n”命令的输出字符串未按预期方式传回……。
问题答案:
.communicate()
每个子流程只能使用一次。因此,在while
循环中使用它不起作用。
相反,您应该p.stdout
直接解析的输出。如果有答案,则每个答案似乎只有一行。
为了防止阻塞,您有3种选择:
-
使用线程。您有一个单独的线程,该线程从
p.stdout
主线程读取数据并将其数据发送到主线程。如果没有可用数据,它将阻止。 -
设置
p.stdout
为非阻塞模式。本质上,您必须执行以下操作:import fcntl, os
fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL,
fcntl.fcntl(p.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
如果在没有可用数据的情况下进行读取,则会出现异常(IOError: [Errno 11] Resource temporarily unavailable
)。
- 使用
select.select()
:p.stdout.readline()
仅当select.select([p.stdout], [], [], <timeout>)[0]
是非空列表时才执行。在那种情况下,保证给定的文件对象有可用的数据并且在读取时不会阻塞。
为了将“垃圾输出”与“有用”输出分开,您可以这样做:
def perform_command(p, cmd, expect):
import select
p.stdin.write(cmd + '\n') # there's no need for a \n at the beginning
while select.select([p.stdout], [], [], 0.05)[0]: # give mplayer time to answer...
output = p.stdout.readline()
print("output: {}".format(output.rstrip()))
split_output = output.split(expect + '=', 1)
if len(split_output) == 2 and split_output[0] == '': # we have found it
value = split_output[1]
return value.rstrip()
然后做
print perform_command(p, 'get_meta_artist', 'ANS_META_ARTIST')
print perform_command(p, 'get_time_pos', 'ANS_TIME_POSITION')