在Python中使用struct模块的pack()选择格式

5 投票
2 回答
2040 浏览
提问于 2025-04-17 04:16

我正在尝试把一段PHP代码转换成Python。

所有的值都是以网络字节顺序(大端)发送的。

基本上,协议规范中的请求是

在这里输入图片描述

而响应是

在这里输入图片描述

对应的PHP代码(相关文档)是:

$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中找到对应的代码(文档链接):

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的那么清晰。协议规定要使用大端格式,而PHP文档明确说明了哪些是大端格式。

可惜的是,我无法理解在Python中应该使用哪种格式。请帮我选择正确的格式。

编辑:没有收到任何回复,所以我想多说几句。

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])

根据协议规范,我应该返回相同的整数。

2 个回答

0

字节序(Endianness)在库参考的第7.3.2.1节中有说明。大端字节序的表示方式是用一个前缀>

3

在PHP中,pack函数里的格式N表示的是一个无符号的32位大端整数。对应的在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

撰写回答