如何使用 Python 流套接字作为代理?
我正在尝试编写一个侦听端口的 python 进程,当客户端连接到它时,它会启动一个执行以下操作的线程:
连接到远程服务 (http://193.108.24.18:8000 /magicFM)
将收到的任何数据传递到连接的客户端(恰好是 Windows Media Player)
故事是,我想在工作时收听广播,但我不能,因为我在另一个国家/地区(仅在全国范围内可用),我无法更改计算机上的代理设置...... 但我有这台服务器,我想将其用作代理。
提前致谢。
这是我到目前为止所做的:
#!/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')
I'm trying to write a python process which listens on a port and when a client connects to it, it starts up a thread which does the following:
Connects to a remote service (http://193.108.24.18:8000/magicFM)
Passes any data received to the connected client (which happens to be Windows Media Player)
The story is that I want to listen to my radio at work, but I cannot because I am in another country(available only nationally) and I cannot change the proxy settings on my computer....
But I have this server which I would like to use as a proxy.
Thanks in advance.
Here's what I did so far:
#!/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()
but it fails... with:
Traceback (most recent call last):
File "./magicfmproxy.py", line 17, in ?
conn.send(chunk)
socket.error: (32, 'Broken pipe')
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,要使用 TCP 连接到远程站点,请使用以下代码
您现在有一个连接到远程服务器的打开套接字。您必须创建一个侦听套接字并等待该套接字建立连接。连接建立后,立即使用
select
多路复用数据流。我现在没有时间,这段代码更多的是它的外观草图。您需要适当的错误处理,并且可能需要在此函数中提供不错的错误消息,但如果没有人提出完整的解决方案,我可能会努力完成此代码。
As a start, to connect to a remote site using TCP, use this code
You now have an open socket connected to a remote server. You would have to create a listen socket and wait on this one for a connection. As soon as the connection is there, multiplex data streams using
select
.I don't have the time right now, this code is more of a sketch how it might look like. You would need proper error handling and maybe nice error messages in this function, but if noone comes up with a complete solution I may make the effort to complete this code.
我只能猜测,但也许你的问题出在客户端。
我不知道您的客户端尝试建立哪些连接,但也许预期的内容和实际传输的内容之间存在冲突:
我看到两种解决方案:
尝试
HTTP/xx 200 OK
等)和标头也发送回您的客户端 - 它应该位于req.headers< 中的某个位置/代码> 左右。
或者
Host:
标头可能必须被替换。I can only guess, but maybe your problem lives on the client side.
I don't know which connections your client tries to establish, but maybe there is a clash between what is expected and what is really transmitted:
urllib2.urlopen()
, or the answer from there doesn't match, the client cancels the connection, letting you have a broken socket.I see two solutions:
Either
HTTP/x.x 200 OK
or such) and the headers back to your client as well - it should be somewhere inreq.headers
or so.Or
urllib2.urlopen()
at all, but just open a regular socket connection to there. But then you'll probably have to tamper with the headers of the request - theHost:
header will probably have to be replaced.扩展 glglgl 答案:你的问题在于破坏协议。
HTTP 协议规定:
GET /magicFM ...
200 OK ...
查看更多详情:http://en.wikipedia.org/wiki/HTTP
urllib2.urlopen
隐藏所有内容不过,您的这种复杂性使它看起来像读取文件一样简单您的客户端希望代理的行为与普通的 http 服务器一样。这里的 urlopen 对你来说是一个错误的抽象。最好的策略是打开到服务器的套接字并启动两个并行循环:(或在一个循环中进行非阻塞读取;或进行异步)
可能有一个复杂性:http协议指定“Host”标头,您的客户端将在请求中将其以代理地址作为值发送给代理,具体取决于您的无线电服务器的行为,您可能需要将客户端请求中的“Host:...”重写为正确的地址(尽管在现代互联网中通常是没关系)。
您会注意到的另一个有趣的副作用是:代理不会包含有关要打开的特定 URL 的任何信息,因为您的媒体客户端将为您提供它们。
To extend glglgl answer: your problem is in breaking protocol.
HTTP protocol specifies:
GET /magicFM ...
200 OK ...
See more for details: http://en.wikipedia.org/wiki/HTTP
urllib2.urlopen
hides all this complication from you making it look as simple as reading file, though your client expect proxy to behave as normal http-server. Hereurlopen
is a wrong abstraction for you. Best strategy would be to open socket to server and start two parallel loops:(or do it in one loop with non-blocking reads; or do asyncio)
There might be a complication: http-protocol specifies "Host" header which your client will send in request to proxy with proxy address as a value, depending on behavior of your radio-server you might need to rewrite "Host: ..." in client request to correct address (though in modern Internet usually it doesn't matter).
Also interesting side effect you will notice would be: proxy would not contain any information about specific URLs to open, as your media client will provide them for you.