2011-10-24 28 views
1

我想寫一個Python進程監聽的端口上,當客戶端連接到它,它啓動一個線程,其執行以下操作:如何使用Python流套接字作爲代理?

  1. 連接到遠程服務(HTTP:/ /193.108.24.18:8000/magicFM)

  2. 通行證接收連接的客戶端(這恰好是Windows媒體播放器)的任何數據

的故事是,我想在聽我的電臺工作,但我不能因爲我在一個其他國家(僅適用於全國性),我不能在我的電腦上更改代理服務器設置.... 但我有這樣的服務器,我想作爲代理使用。

在此先感謝。

這裏就是我所做的迄今:

#!/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') 
+0

有很多這樣的軟件,例如tcptunnel – hamstergene

+0

您也可以使用Putty創建SOCKS代理,然後使用Proxifier強制WMP使用您剛創建的SOCKS代理。 –

+1

爲了將來兼容,請將''0.0.0.0''更改爲''''並將'AF_INET'更改爲'AF_INET6'。它仍然適用於IPv4,但也可以與IPv6一起使用。 – glglgl

回答

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複用數據流。

我沒有時間,現在,這個代碼是更草圖如何可能看起來像。您需要正確的錯誤處理,也許漂亮的錯誤訊息,這個功能,但如果沒有人來了一個完整的解決方案我可以作出努力來完成這個代碼。

+0

對,唯一想不到的是如何連接到http://193.108.24.18:8000/magicFM – ren

+0

這是一種http服務,是否可以使用urllib2下載數據塊並將其發送給客戶端? – ren

+0

這意味着使用端口8000連接到主機193.108.24.18,並獲取正確的URL。也許你最好使用URL/HTTP模塊之一。如果您想手動完成,請調用connectoToHost(「193.108.24.18」,8000)並在套接字中寫入「GET magicFM HTTP/1.0 \ n \ n」。 – hochl

1

我只能猜測,但也許你的問題住在客戶端。

我不知道哪個連接您的客戶端嘗試建立,但也許有什麼之間的預期,什麼是真正傳輸的衝突:

  • 您從您的客戶端,這可能將連接一些請求數據。
  • 如果這些數據不發送到流與urllib2.urlopen()的數據,或者答案從那裏不匹配匹配,客戶取消了連接,讓你有一個破碎的插座。

我看到了兩個解決方案:

要麼

  • 嘗試答案線(HTTP/x.x 200 OK或此類)和頭髮送回客戶端,以及 - 它應該是在req.headers某處或所以。

或者

  • 不做urllib2.urlopen()可言,而只是打開一個普通插座連接到那裏。但是,您可能不得不篡改請求的標題--標題可能不得不被替換。
0

要擴展glglgl的答案:你的問題在於破壞協議。

HTTP協議指定:http://en.wikipedia.org/wiki/HTTP

  • 用戶請求使用元數據GET /magicFM ...
  • 服務器響應200 OK ...
  • 服務器繼續與實際數據

查看更多細節響應urllib2.urlopen隱藏了所有這些複雜功能,使其看起來像讀取文件一樣簡單,儘管您的客戶端期望代理像正常的http服務器一樣工作。這裏urlopen對你來說是一個錯誤的抽象。最好的策略是打開套接字服務器,並啓動兩個並行循環:

  • 從客戶端讀取,寫入服務器
  • 從服務器讀取,寫入到客戶端

(或做在一個循環與非阻塞讀取;或做asyncio)

可能有一個複雜:http協議指定「主機」標題,您的客戶端將請求代理與代理地址作爲值,取決於您的行爲您可能需要重寫無線電服務器e「主持人:......」在客戶端請求糾正地址(儘管在現代互聯網中通常無關緊要)。

您會注意到的另一個有趣的副作用是:代理不會包含任何關於要打開的特定URL的信息,因爲您的媒體客戶端將爲您提供它們。

+0

關鍵是http是雙向的:客戶端向服務器寫入請求,服務器向客戶端寫入響應。 –

+0

是的,我明白這一點。如果你看看我目前的解決方案,你會注意到我考慮到了這一點,但是仍然有一些我錯過了:s – ren

+0

你目前的解決方案是從服務器到客戶端進行單向數據傳輸。 GET/magicFM HTTP/1.0 \ n \ n''不足以觸發流式傳輸,服務器可能會從客戶端獲得其他東西。您可以通過執行telnet 193.108.24.18 8000'並在其中輸入GET/magicFM HTTP/1.0進行檢查。 (我甚至不能ping通這個IP,因爲在IP中的錯誤或因爲我在歐洲) –