我有一个简单的C程序,它的工作方式如下: 请求输入 打印出来 问另一个输入 再次打印
现在我使用python来调用这个程序。
import subprocess
sobj = subprocess.Popen("./cprog", stdin = subprocess.PIPE, stdout = subprocess.PIPE)
sobj.stdin.write("2 3\n")
sobj.stdin.close()
sobj.stdout.read()
这很好用。同样,沟通其工作正常。
但是当我尝试做这样的事情时,它将不起作用
sobj = subprocess.Popen("./cprog", stdin = subprocess.PIPE, stdout = subprocess.PIPE)
sobj.stdout.readline()
sobj.stdin.write("2 3\n")
sobj.stdin.close()
sobj.stdout.read()
以下是一些事情: 我看到了pexpect,但我认为我们应该提前提出要求的程序。 2.我可以重新打开关闭的子流程管道吗?
我使用上面的脚本作为CGI,我不知道为什么,但subprocess.call将不起作用。任何人都可以解释原因吗?
编辑:
我正在做一个基于Web的项目,用户在C,C ++或JAVA中编写代码并在浏览器上执行它们。所以首先我想到使用PHP,但我找不到一种方法来调用程序并以交互方式运行它们。然后我看到了python子进程模块。当我使用subprocess.call时,一切都在解释器中正常工作。但是同样的python程序在保存为.cgi并在浏览器中打开时它无效。然后我开始查看subprocess.popen。但有了这个,我需要在开始时提供所有输入,然后运行代码。我想要做的是在浏览器中运行交互式会话。
编辑2: 所以我想要的是浏览器中的用户运行程序,并在需要时在文本框中输入输入,并且输入被重定向到子进程的stdin并基于它输出。
编辑3:cprog.c
#include <stdio.h>
int main() {
int x;
printf("Enter value of x: \n");
scanf("%d", &x);
printf("Value of x: %d\n", x);
return 0;
}
答案 0 :(得分:0)
我假设你的C应用程序显示一个提示,并希望用户在同一行输入他们的输入,并且在你上面的readline()
调用中你试图获得提示。
如果是这种情况,readline()
将永远阻止,因为它正在等待换行符并且从未看到它。如果你将这个调用转换为一个简单的read(X)
(其中X
是一次读取的字节数),那么你可能会有更好的运气,尽管你应该处理部分输入(即循环)收集输入,直到你看到整个提示)。您可能看到的唯一其他问题是,如果C应用程序在提示用户之前没有刷新输出,但我希望您在交互式会话中也能看到该问题,如果是这种情况。
当在像Apache这样的网络服务器的上下文中运行时,使用像subprocess
这样的东西通常是一个坏主意,因为它们涉及分支额外的进程,这通常是一件非常棘手的事情。这是因为fork进程复制了父进程的大部分状态,有时这会导致问题。我不是说它不会起作用,我只是说如果你不小心你可以为自己制造一些微妙的问题,如果这就是你使用{{1 }}
但是,为了提供更多有用的建议,您需要准确描述调用子流程时看到的错误。例如,很可能会抛出异常,这可能会出现在您的网络服务器日志中 - 再现这将是一个良好的开端。
答案 1 :(得分:0)
当我直接通过终端运行C程序时,它工作正常。但是,当我使用上面提供的第二个代码运行相同的程序时,没有任何打印。
您没有看到任何输出的原因是当程序以非交互模式运行时,C stdio使用块缓冲。见my answer that demonstrate several solutions: pty
, stdbuf
, pexpect
。如果您可以更改C代码,那么您也可以fflush the output explicitly or make it unbuffered。
如果您可以一次提供所有输入并且输出有界,那么您可以使用.communicate()
:
from subprocess import Popen, PIPE
p = Popen(["./cprog"], stdin=PIPE, stdout=PIPE, stderr=PIPE,
universal_newlines=True)
out, err = p.communicate("2\n")
所以我想要的是浏览器中的用户运行程序,并在需要时在文本框中输入输入,并且输入被重定向到子进程的stdin并基于它输出。
#!/usr/bin/python
"""WebSocket CLI interface.
Install: pip install twisted txws
Run: twistd -ny wscli.py
Visit http://localhost:8080/
"""
import sys
from twisted.application import strports # pip install twisted
from twisted.application import service
from twisted.internet import protocol
from twisted.python import log
from twisted.web.resource import Resource
from twisted.web.server import Site
from twisted.web.static import File
from txws import WebSocketFactory # pip install txws
class Protocol(protocol.Protocol):
def connectionMade(self):
from twisted.internet import reactor
log.msg("launch a new process on each new connection")
self.pp = ProcessProtocol()
self.pp.factory = self
reactor.spawnProcess(self.pp, command, command_args)
def dataReceived(self, data):
log.msg("redirect received data to process' stdin: %r" % data)
self.pp.transport.write(data)
def connectionLost(self, reason):
self.pp.transport.loseConnection()
def _send(self, data):
self.transport.write(data) # send back
class ProcessProtocol(protocol.ProcessProtocol):
def connectionMade(self):
log.msg("connectionMade")
def outReceived(self, data):
log.msg("send stdout back %r" % data)
self._sendback(data)
def errReceived(self, data):
log.msg("send stderr back %r" % data)
self._sendback(data)
def processExited(self, reason):
log.msg("processExited")
self._sendback('program exited')
def processEnded(self, reason):
log.msg("processEnded")
def _sendback(self, data):
self.factory._send(data)
command = './cprog'
command_args = [command]
application = service.Application("ws-cli")
echofactory = protocol.Factory()
echofactory.protocol = Protocol
strports.service("tcp:8076:interface=127.0.0.1",
WebSocketFactory(echofactory)).setServiceParent(application)
resource = Resource()
resource.putChild('', File('index.html'))
strports.service("tcp:8080:interface=127.0.0.1",
Site(resource)).setServiceParent(application)
其中index.html
:
<!doctype html>
<title>Send input to subprocess using websocket and echo the response</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js">
</script>
<script>
// send keys to websocket and echo the response
$(document).ready(function() {
// create websocket
if (! ("WebSocket" in window)) WebSocket = MozWebSocket; // firefox
var socket = new WebSocket("ws://localhost:8076");
// open the socket
socket.onopen = function(event) {
// show server response
socket.onmessage = function(e) {
$("#output").text(e.data);
}
// sent input
$("#entry").keyup(function (e) {
socket.send($("#entry").attr("value")+"\n");
});
}
});
</script>
<pre id=output>Here you should see the output from the command</pre>
<input type=text id=entry value="123">
cprog.c
:
#include <stdio.h>
int main() {
int x = -1;
setbuf(stdout, NULL); // make stdout unbuffered
while (1) {
printf("Enter value of x: \n");
if (scanf("%d", &x) != 1)
return 1;
printf("Value of x: %d\n", x);
}
return 0;
}