Python 模块运行但函数无法运行

标签 python raspberry-pi network-programming streaming

尽管我了解 Python 语法并编写了一些用于数据处理和分析(光谱和图像)的脚本来完成这项工作,但我从未真正使用过网络或流媒体,我想我必须承认我的编程技能相当低。也许,我正在尝试处理超出我当前技能允许的事情,但这可能是开发的常见情况。

无论如何,我正在开发(另一个)GUI 客户端来控制 Raspberry Pi 相机 - 既为了乐趣又为了学习。长话短说,我想从这个 GUI 运行一个流式 http 服务器。我寻求一个现成的解决方案并遵循这个食谱

http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server

PAGE="""\
<html>
description of webpage
</html>
"""

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
    output = StreamingOutput()
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

好的,如果该代码作为独立应用程序运行,则可以正常工作。但是如果我尝试让它作为一个函数运行,即如果我想在类构造之后这样做

def main():
    with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
            output = StreamingOutput()
            camera.start_recording(output, format='mjpeg')
            try:
                address = ('', 8000)
                server = StreamingServer(address, StreamingHandler)
                server.serve_forever()
            except(KeyboardInterrupt):
                camera.stop_recording()

if __name__ == '__main__':
    main()

那么尽管创建了输出和服务器对象,它也不会进行流式传输。我真的很困惑,请问有人可以回答为什么吗? - 如果答案很简单并且问题很愚蠢,我不会感到惊讶,因此,如果有人可以推荐一些教程或简单阅读有关编写用于流式传输/接收数据的服务器/客户端的内容,我将不胜感激。

另一件事是,我希望能够根据请求终止该服务器 - 为此,我想最好的解决方案是使用线程模块并使 gui 和服务器在单独的线程中运行? 非常感谢

N

最佳答案

你是对的,第一个答案非常简单。

问题在于,当定义变量 output 的代码位于 StreamingHandler 中时,该变量不在 scope 内一个名为 main 的函数。

output = 5

def test():
    print(output)

# the following statement runs fine, output is in scope because it
# was defined in the top-level scope   
test()

def test_2():
    print(output_2)

def main():
    output_2 = 6
    test_2()

# error! test_2 doesn't know the value of output_2 because the
# output_2 variable was declared within main()
main()

因此,您需要找到一种方法将 output 变量传递到服务器。我的方法是在 StreamingHandler 中将输出声明为类变量,并在实例化新的 StreamingServer 时添加输出作为参数,如下所示:

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server

PAGE="""\
<html>
description of webpage
</html>
"""

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    output = None

    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with StreamingHandler.output.condition:
                        StreamingHandler.output.condition.wait()
                        frame = StreamingHandler.output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True
    def __init__(self, address, handler, output):
        handler.output = output
        super().__init__(address, handler)

def main():
    with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
            output = StreamingOutput()
            camera.start_recording(output, format='mjpeg')
            try:
                address = ('', 8000)
                server = StreamingServer(address, StreamingHandler, output)
                server.serve_forever()
            except(KeyboardInterrupt):
                camera.stop_recording()

if __name__ == '__main__':
    main()        

我现在把关于杀死服务器的问题留给我博学的同事。

关于Python 模块运行但函数无法运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50354034/

相关文章:

python - python中的网络数据包长度

linux - 在主动网络服务器中接受连接的传统方式(使用异步 IO)

python - py2neo:具有多个键/值的 Graph.find_one

python - 如何使用python获取arduino端口

python - 在树莓派上运行 puppeteer 时出现 OSError

无限循环中的Python用户输入太慢,容易混淆

python - 在 Python 中按值和键排序字典?

python - 从 Pandas 数据框中获取列名,包括索引名称

python - 数据加密静态加密

c++ - 网络编程问题 - 缓冲区只会向服务器发送一次