2011-10-13 68 views
5

我想將PHP代碼轉換爲python。在Python中使用結構模塊在pack()中選擇格式

所有的值都以網絡字節順序(大端)發送。

基本上,在協議規範的請求是

enter image description here

和響應是

enter image description here

通訊PHP代碼(corresponding DOC)爲:

$transaction_id = mt_rand(0,65535); 
$current_connid = "\x00\x00\x04\x17\x27\x10\x19\x80"; 
$fp = fsockopen($tracker, $port, $errno, $errstr); 
$packet = $current_connid . pack("N", 0) . pack("N", $transaction_id); 
fwrite($fp,$packet); 

我試圖找到在python相應的代碼(for doc):

transaction_id = random.randrange(1,65535) 
packet = "\x00\x00\x04\x17\x27\x10\x19\x80" 
packet = packet + struct.pack("i", 0) + struct.pack("i", transaction_id) 
clisocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
clisocket.sendto(packet, ("tracker.istole.it", 80)) 

在響應中,我應該得到我在我沒有收到請求發送相同TRANSACTION_ID。所以,我的猜測是,我沒有使用正確的格式打包。

此外,python文檔並不像PHP那樣清晰。該協議指定使用Big Endian格式& PHP doc明確指出哪些是Big-Endian的。

不幸的是,我無法理解在python中使用哪種格式。請幫助我選擇corrent格式。

編輯: 沒有得到任何答覆,所以我會說更多。

import struct 
import socket 
import random 

clisocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
packet = "\x00\x00\x04\x17\x27\x10\x19\x80" 
transaction_id = random.randrange(1,65535) 
print transaction_id 
packet = packet+struct.pack(">i", 0) 
packet = packet+struct.pack(">i", transaction_id) 

clisocket.sendto(packet, ("tracker.istole.it", 80)) 
res = clisocket.recv(16) 

print struct.unpack(">i", res[12:16]) 

根據協議規範,我應該返回相同的INTEGER。

+0

用於該協議的完整文檔是在http://bittorrent.org/beps/bep_0015.html#udp-tracker-protocol –

+0

示出了如何使用來檢索數據的示例該協議位於http://linux-junky.blogspot.com/2011/10/get-seeds-peers-completed-info-from.html –

回答

3

php pack function格式N表示無符號的32位big-endian整數。 對應的Python struct.pack格式爲>L

您爲協議發佈的圖像顯示connection_id應該是64位(無符號)整數:Python struct.pack格式Q

所以:

clisocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
connection_id=0x41727101980 
action=0 
# transaction_id = random.randrange(1,65535) 
transaction_id = 12345  
print(transaction_id) 
# 12345 

packet=struct.pack(">QLL",connection_id,action,transaction_id) 
print(repr(packet)) 
# "\x00\x00\x04\x17'\x10\x19\x80\x00\x00\x00\x00\x00\x0009" 

clisocket.sendto(packet, ("tracker.istole.it", 80)) 
res = clisocket.recv(16) 
action,transaction_id,connection_id=struct.unpack(">LLQ",res) 
print(action) 
# 0 
print(transaction_id) 
# 12345 
print(connection_id) 
# 2540598739861590271 
+0

我希望我可以多次提醒你。非常感謝你。 –

+1

請問您爲什麼選擇64位整數的Q(無符號長整數)和32位整數的L(無符號長整數)?我需要知道這一點,以便在做這件小事時我不會陷入困境。 –

+1

64位是8個字節。標題爲「Standard Size」的[struct.pack format format table](http://docs.python.org/library/struct.html#format-characters)的第三列顯示了哪些格式對應8個字節。 8字節選項是'q','Q'和'd'。既然我們想要無符號整數,'Q'是正確的選擇。同樣,32位是4字節。有四種選擇,'我','我','l','L'。我認爲* transaction_id應該是無符號的,這樣就可以將選擇範圍縮小爲「I」或「L」。它們是等價的。任何一個工作。 – unutbu

0

Endianness在§7.3.2.1 of the library reference中描述。大端包裝的前綴爲>

+0

那麼,我該如何使用? –

+1

[define:prefix](http://www.google.com/search?q=define%3Aprefix) –

+1

http://sprunge.us/PBLf是我的代碼,但我沒有返回相同的整數WHILE PHP代碼工作得很好。 –