1

次のように機能する単純なCプログラムがあります。入力を要求する印刷する別の入力を要求するもう一度印刷する

ここで、iamは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()

以下にいくつかのことを示します。1。pexpectを見ましたが、プログラムが求めるものを事前に提供する必要があると思います。2.閉じたサブプロセスパイプを再び開くことはできますか?

Iamは上記のスクリプトをCGIとして使用していますが、理由はわかりませんが、subprocess.callはその中で機能しません。誰かが理由を説明できますか?

編集:

Iamは、ユーザーがC、C ++、またはJAVAのいずれかでコードを記述し、それらをブラウザーで実行するWebベースのプロジェクトを実行しています。そこで、最初は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;
 }
4

2 に答える 2

0

ターミナルから直接Cプログラムを実行すると、正常に動作します。しかし、私が提供した2番目のコードで同じプログラムを実行すると、何も印刷されません。

出力が表示されない理由は、プログラムが非対話モードで実行されているときに、C stdio がブロック バッファリングを使用するためです。いくつかの解決策を示す私の回答をptystdbufpexpect参照してください: , , . C コードを変更できる場合は、出力を明示的にフラッシュするか、バッファリングしないようにすることもできます。

すべての入力を一度に提供でき、出力が制限されている場合は、次を使用できます.communicate()

from subprocess import Popen, PIPE

p = Popen(["./cprog"], stdin=PIPE, stdout=PIPE, stderr=PIPE,
          universal_newlines=True)
out, err = p.communicate("2\n")

だから私が欲しいのは、ユーザーがブラウザでプログラムを実行し、必要に応じて提供されるテキストボックスに入力を入力し、その入力がサブプロセスの標準入力にリダイレクトされ、それに基づいて出力されることです。

ws-cli の例に基づく:

#!/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;
}
于 2013-01-15T10:53:43.797 に答える
0

C アプリケーションがプロンプトを表示し、ユーザーが同じ行に入力することを期待しており、readline()上記の呼び出しでプロンプトを取得しようとしていると想定しています。

この場合、readline()改行文字を待っていてそれを見ないため、永久にブロックされます。この呼び出しを単純なものread(X)(Xは一度に読み取るバイト数) に変換すると、運が良くなる可能性がありますが、部分的な入力に対処する必要があります (つまり、全体が表示されるまで入力を収集するループを繰り返します)。促す)。他に発生する可能性がある唯一の問題は、C アプリケーションがユーザーにプロンプ​​トを表示する前に出力をフラッシュしない場合ですが、その場合は対話型セッションでもその問題が発生することが予想されます。

Apache のような Web サーバーのコンテキストで実行する場合、subprocess追加のプロセスをフォークする必要があり、多くの場合、管理が非常に難しいため、 のようなものを使用することは一般的に悪い考えです。これは、フォーク プロセスが親の状態の多くを複製し、これが問題を引き起こす場合があるためです。うまくいかないと言っているのではありません。注意しないと微妙な問題が発生する可能性があると言っているだけですsubprocess

ただし、さらに役立つアドバイスを提供するには、subprocess を呼び出したときに表示されるエラーを正確に説明する必要があります。たとえば、例外がスローされる可能性が非常に高く、これはおそらく Web サーバーのログに記録されます。ここでそれを再現することから始めるとよいでしょう。

于 2013-01-12T10:24:56.737 に答える