简体   繁体   English

python发送http响应

[英]python sending http response

I am trying to write a very simple HTTP server which sends a video being streamed server side. 我正在尝试编写一个非常简单的HTTP服务器,该服务器发送正在服务器端流式传输的视频。 When a client connects, the get_video program (fictional) is started in another process and its stdout is being piped to us (under the assumption get_video sends/streams video to stdout). 当客户端连接时,get_video程序(虚构的)将在另一个进程中启动,并且其stdout将通过管道传递给我们(假设get_video将视频发送/流式传输到stdout)。 I am using subprocess.Popen() for this. 我为此使用subprocess.Popen()

import subprocess, socket

def send_video(sock, programme_id):
    p = subprocess.Popen(["get_video","--pid",programme_id], stdout=subprocess.PIPE)
    sock.send("HTTP/1.1 200 OK\nContent-type: application/octet-stream\n\n")
    while True:
        chunk = p.stdout.read(1024)
        if chunk:
            try:
                sock.send(chunk)
            except Exception:
                pass
        else:
            break

def main():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('',8080))
    s.listen(5)

    while True:
        client, address = s.accept()
        data = client.recv(1024)
        send_video(client, "123456")
        client.close()

if __name__ == "__main__":
    main()

This barely works. 这几乎行不通。 If I issue an HTTP request using wget http://localhost:8080/blah.mp4 the whole thing does as expected - the video is streamed to the client's socket and appended to the new file, blah.mp4. 如果我使用wget http://localhost:8080/blah.mp4发出HTTP请求,则整个过程将按预期进行-视频将流式传输到客户端的套接字并附加到新文件blah.mp4。

However, if I create a dummy HTML page with <a href="http://localhost:8080/blah/mp4">download</a> and then try 'save target/link as...' on that link, the get_video program is invoked twice. 但是,如果我使用<a href="http://localhost:8080/blah/mp4">download</a>创建了一个虚拟HTML页面,然后在该链接上尝试“将目标/链接另存为...”, get_video程序被调用两次。 The second time being when the video is actually sent to the client's socket. 第二次是将视频实际发送到客户端的套接字时。 There must be some sort of buffering going on. 必须进行某种缓冲。

Notice the try/except block in send_video() . 注意send_video()try/except块。 I was getting a 'broken pipe' error before (with the dummy HTML page method), indicating the client's socket wasn't there to be written to. 之前(使用虚拟HTML页面方法),我遇到了“管道破裂”错误,指示该客户端的套接字没有被写入。 I put the try/except there to try and ignore it. 我把try/except放在那儿尝试忽略它。

I am fairly confused. 我很困惑。 The HTTP requests look the same, I'm not sure what my browser (Firefox) is doing differently to cause this. HTTP请求看起来相同,我不确定我的浏览器(Firefox)所做的不同以导致此问题。

Any ideas? 有任何想法吗?

Edit: 编辑:

The header from wget: wget的标头:

GET /blah.mp4 HTTP/1.0
User-Agent: Wget/1.12 (linux-gnu)
Accept: */*
Host: 192.168.1.2:8080
Connection: Keep-Alive

The header from html dummy page: html虚拟页面的标题:

GET /blah.mp4 HTTP/1.1
Host: 192.168.1.2:8080
User-Agent: Mozilla/5.0 (blah) Gecko/blah Firefox/3.6.16
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

The python server reported only one of each, but Wireshark reported 2 GET requests for the dummy html link method. python服务器只报告了每个,但Wireshark报告了2个针对虚拟html链接方法的GET请求。 I don't see anything obvious here... 我在这里看不到任何明显的东西...

It dawned on me that, because the browser sends a GET followed by a FIN,ACK after the 'save target as...' has been clicked on the link, then that'll be what is causing the broken pipe error. 我突然意识到,因为在链接上单击“目标另存为...”后,浏览器发送GET,然后发送FIN,ACK,这将是导致管道断开错误的原因。 It is when you choose where you want to save the file and hit 'OK' button in the browser that another GET is issued. 当您选择要保存文件的位置并在浏览器中单击“确定”按钮时,将发出另一个GET。 What was happening was I was still stuck in that while True loop once I had detected the broken pipe. 发生的事情是, while True我检测到管道破裂时,我仍然停留在while True循环中。 So I was continuing to read from the Popen object and failing to send it to the client every time. 因此,我一直在继续读取Popen对象,并且每次都没有将其发送给客户端。 Once this finished, the next GET was able to continue and the transfer was then successful. 完成此操作后,下一个GET就可以继续,然后传输成功。 Phew. ew

In short, the working code: 简而言之,工作代码:

import subprocess, socket

def send_video(sock, programme_id):
    p = subprocess.Popen(["get_video","--pid",programme_id], stdout=subprocess.PIPE)
    sock.send("HTTP/1.1 200 OK\nContent-type: application/octet-stream\n\n")
    while True:
        chunk = p.stdout.read(1024)
        if chunk:
            try:
                sock.send(chunk)
            except socket.error, e:
                sock.close()
                break
        else:
            break

def main():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('',8080))
    s.listen(5)

    while True:
        client, address = s.accept()
        data = client.recv(1024)
        send_video(client, "123456")
        client.close()

if __name__ == "__main__":
    main()

Thanks. 谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM