如何使用Python流式套接字作为代理?

时间:2011-10-24 12:08:46

标签: python sockets proxy streaming

我正在尝试编写一个侦听端口的python进程,当客户端连接到它时,它会启动一个执行以下操作的线程:

  1. 连接远程服务(http://193.108.24.18:8000/magicFM)

  2. 将收到的所有数据传递给连接的客户端(恰好是Windows Media Player)

  3. 故事是我想在工作中收听我的收音机,但我不能,因为我在另一个国家(仅在全国范围内可用),我无法更改计算机上的代理设置.... 但我有这个服务器,我想用作代理。

    提前致谢。

    以下是我到目前为止所做的事情:

    #!/usr/bin/env python
    import socket, urllib2
    
    TCP_IP = '0.0.0.0'
    TCP_PORT = 5566
    BUFFER_SIZE = 16 * 1024  #16 kb/s
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((TCP_IP, TCP_PORT))
    s.listen(1)
    conn, addr = s.accept()
    print 'Connection address:', addr
    req = urllib2.urlopen('http://193.108.24.18:8000/magicFM')
    
    while 1:
        chunk = req.read(BUFFER_SIZE)
        if not chunk: break
        conn.send(chunk)
    
    
    conn.close()
    

    但它失败了...:

    Traceback (most recent call last):
      File "./magicfmproxy.py", line 17, in ?
        conn.send(chunk)
    socket.error: (32, 'Broken pipe')
    

3 个答案:

答案 0 :(得分:2)

首先,要使用TCP连接到远程站点,请使用此代码

import socket, struct

def connectToHost(host, port=80, timeout=0):
    try:
            sock=socket.socket()
            timeval=struct.pack("2I", timeout, 0)
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, timeval)
            sock.connect((host, port))
            return sock
    except:
            return None

您现在有一个连接到远程服务器的开放式套接字。您必须创建一个侦听套接字并等待此套接字进行连接。只要连接存在,就使用select多路复用数据流。

我现在没有时间,这段代码更像是草图的样子。您需要在此函数中进行正确的错误处理和错误消息,但如果没有人提供完整的解决方案,我可能会努力完成此代码。

答案 1 :(得分:1)

我只能猜测,但也许你的问题存在于客户端。

我不知道您的客户尝试建立哪些连接,但可能在预期内容和实际传输内容之间存在冲突:

  • 您从客户端获得了一个连接,可能会发送一些请求数据。
  • 如果这些与您使用urllib2.urlopen()发送到流的数据不匹配,或者那里的答案不匹配,则客户端取消连接,让您的套接字断开。

我看到两个解决方案:

无论

  • 尝试将答案行(HTTP/x.x 200 OK或类似内容)和标题发送回客户端 - 它应该位于req.headers左右。

  • 根本不做urllib2.urlopen(),只是打开常规的套接字连接。但是,您可能不得不篡改请求的标头 - Host:标头可能必须被替换。

答案 2 :(得分:0)

扩展glglgl回答:你的问题在于破解协议。

HTTP协议指定:

  • 用户请求GET /magicFM ...
  • 包含元数据200 OK ...
  • 的服务器响应
  • 服务器继续回复实际数据

详情请见http://en.wikipedia.org/wiki/HTTP

urllib2.urlopen隐藏了所有这些复杂功能,使其看起来像读取文件一样简单,尽管您的客户端希望代理能够像普通的http服务器一样运行。这里urlopen对你来说是错误的抽象。最好的策略是打开socket到服务器并启动两个并行循环:

  • 从客户端读取,写入服务器
  • 从服务器读取,写入客户端

(或使用非阻塞读取在一个循环中执行;或执行asyncio)

可能存在复杂问题:http-protocol指定客户端将请求代理地址作为值发送给客户端的“主机”标头,具体取决于您可能需要重写“无线电服务器”的行为。 ..“在客户要求纠正地址(虽然在现代互联网上通常无关紧要)。

您会注意到的另一个有趣的副作用是:代理不会包含有关要打开的特定URL的任何信息,因为您的媒体客户端会为您提供这些信息。