Python 2.7 如何在Twisted[autobahn]websocket服务器中实时传输输出?

Python 2.7 如何在Twisted[autobahn]websocket服务器中实时传输输出?,python-2.7,twisted,autobahn,Python 2.7,Twisted,Autobahn,我想使用subprocess.Popen()执行一个C程序,并实时流化它的输出并将其发送到客户端。但是,输出是缓冲的,并在执行结束时一起发送(阻塞性质)。如何实时接收输出,然后在Twisted Autobahn中立即发送 def onConnect(self, request): try: self.cont_name = ''.join(random.choice(string.lowercase) for i in range(5)) self.fi

我想使用subprocess.Popen()执行一个C程序,并实时流化它的输出并将其发送到客户端。但是,输出是缓冲的,并在执行结束时一起发送(阻塞性质)。如何实时接收输出,然后在Twisted Autobahn中立即发送

def onConnect(self, request):
    try:
        self.cont_name = ''.join(random.choice(string.lowercase) for i in range(5)) 
        self.file_name = self.cont_name
        print("Connecting...")
    except Exception:
        print("Failed"+str(Exception))    

def onOpen(self):
    try:
        print("open")
    except Exception:
        print("Couldn't create container")

def onMessage(self, payload,isBinary=False):
        cmd = "docker exec "+self.cont_name+" /tmp/./"+self.file_name
        a = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE, bufsize=1)
        for line in iter(a.stdout.readline, b''):
            line = line.encode('utf8')
            self.sendMessage(line)

def onClose(self, wasClean, code, reason):
    try:
        print("Closed container...")
    except Exception:
        print(str(Exception))    
当使用subprocess执行docker命令时,c代码的整个输出将立即返回,而不是按原样返回。例如:

#include <stdio.h>
#include <unistd.h>
int main(){
int i=0;
for(i=0;i<5;i++){
    fflush(stdout);
    printf("Rounded\n");
    sleep(3);
}
}
#包括
#包括
int main(){
int i=0;

对于(i=0;i而言,错误行为来自此方法中的循环:

def onMessage(self, payload,isBinary=False):
        cmd = "docker exec "+self.cont_name+" /tmp/./"+self.file_name
        a = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE, bufsize=1)
        for line in iter(a.stdout.readline, b''):
            line = line.encode('utf8')
            self.sendMessage(line)
Twisted是一个协作多任务系统。默认情况下,所有东西都在一个线程(“反应线程”)中运行。这意味着所有代码都必须周期性地(通常是快速地)放弃控制,以便其他代码(应用程序代码或Twisted实现代码)获取运行的机会。此函数中的循环读取子进程并尝试使用Autobahn API发送数据-一次又一次,从不放弃控制

阻止对Popen对象的读取也可能会导致问题。您不知道读取将阻止多长时间,因此不知道阻止其他代码在反应器线程中运行多长时间。您可以将Popen读取移动到一个新线程,在该线程中它们不会阻止反应器线程:

def onMessage(self, payload,isBinary=False):
    cmd = "docker exec "+self.cont_name+" /tmp/./"+self.file_name
    popen_in_thread(
        lambda line: reactor.callFromThread(
            lambda: self.sendMessage(line.encode("utf-8"))
        ),
        [cmd], shell=True, stdout=subprocess.PIPE, bufsize=1
    )

def popen_in_thread(callback, *args, **kwargs):
    def threaded():
        a = subprocess.Popen(*args, **kwargs)
        for line in iter(a.stdout.readline, b''):
            callback(line)
    reactor.callInThread(threaded)
或者,更好地使用Twisted自己的流程支持:

def onMessage(self, payload,isBinary=False):
    class ProcessLinesToMessages(ProcessProtocol):
        def outReceived(self, output):
            buf = self.buf + output
            lines = buf.splitlines()
            self.buf = lines.pop()
            for line in lines:
                self.sendMessage(line.encode("utf-8"))
            while True:
                line, self.buf = self.buf.splitline
    reactor.spawnProcess(
        ProcessLinesToMessages(),
        "docker",
        [
            "docker",
            "exec",
            self.cont_name,
            "/tmp/./ + self.file_name,
        ],
    )

(两个版本都没有经过测试,希望想法很清楚)

错误行为来自此方法中的循环:

def onMessage(self, payload,isBinary=False):
        cmd = "docker exec "+self.cont_name+" /tmp/./"+self.file_name
        a = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE, bufsize=1)
        for line in iter(a.stdout.readline, b''):
            line = line.encode('utf8')
            self.sendMessage(line)
Twisted是一个协作多任务系统。默认情况下,所有东西都在一个线程(“反应线程”)中运行。这意味着所有代码都必须周期性地(通常是快速地)放弃控制,以便其他代码(应用程序代码或Twisted实现代码)获取运行的机会。此函数中的循环读取子进程并尝试使用Autobahn API发送数据-一次又一次,从不放弃控制

阻止对Popen对象的读取也可能会导致问题。您不知道读取将阻止多长时间,因此不知道阻止其他代码在反应器线程中运行多长时间。您可以将Popen读取移动到一个新线程,在该线程中它们不会阻止反应器线程:

def onMessage(self, payload,isBinary=False):
    cmd = "docker exec "+self.cont_name+" /tmp/./"+self.file_name
    popen_in_thread(
        lambda line: reactor.callFromThread(
            lambda: self.sendMessage(line.encode("utf-8"))
        ),
        [cmd], shell=True, stdout=subprocess.PIPE, bufsize=1
    )

def popen_in_thread(callback, *args, **kwargs):
    def threaded():
        a = subprocess.Popen(*args, **kwargs)
        for line in iter(a.stdout.readline, b''):
            callback(line)
    reactor.callInThread(threaded)
或者,更好地使用Twisted自己的流程支持:

def onMessage(self, payload,isBinary=False):
    class ProcessLinesToMessages(ProcessProtocol):
        def outReceived(self, output):
            buf = self.buf + output
            lines = buf.splitlines()
            self.buf = lines.pop()
            for line in lines:
                self.sendMessage(line.encode("utf-8"))
            while True:
                line, self.buf = self.buf.splitline
    reactor.spawnProcess(
        ProcessLinesToMessages(),
        "docker",
        [
            "docker",
            "exec",
            self.cont_name,
            "/tmp/./ + self.file_name,
        ],
    )

(两个版本都没有经过测试,希望想法是明确的)

你的问题大体上是有道理的,但范围太广,以至于不清楚你的问题在哪里,也不清楚什么建议可以帮助你克服。你能提供一些示例代码吗?最好是类似的。@Jean-PaulCalderone我添加了一些代码。请看一下。谢谢你的问题大体上是有道理的t范围太广,以至于不太清楚您遇到的问题在哪里,或者什么建议可以帮助您克服它。您能提供一些示例代码吗?最好是类似的内容。@Jean-PaulCalderone我添加了一些代码。请看一看。Thankscan deffered在这种情况下可以使用吗?Deferred代表一个未来的结果lt.您希望从正在进行的流程中流式传输数据。这两件事不太协调。但是,您可能希望使用管道,而不是像我在本示例代码中所做的那样手工制作回调。在这种情况下可以使用deffered吗?Deferred表示一个单独的未来结果。您希望从正在进行的流程中流式传输数据。这两件事不需要不过,您可能希望使用管道,而不是像我在这个示例代码中所做的那样手工制作回调。