Reputation: 115
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')
Upvotes: 1
Views: 3697
Reputation: 570
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. Here urlopen
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.
Upvotes: 0
Reputation: 91099
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 in req.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 - the Host:
header will probably have to be replaced.Upvotes: 1
Reputation: 12950
As a start, to connect to a remote site using TCP, use this code
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
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.
Upvotes: 2