【问题标题】:Choosing format in pack() using struct module in python在 python 中使用 struct 模块在 pack() 中选择格式
【发布时间】:2011-12-07 04:34:53
【问题描述】:

我正在尝试将 PHP 代码转换为 python。

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

协议规范中的REQUEST基本上是

响应是

对应的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 文档明确说明了哪些是 Big-Endian 格式。

遗憾的是,我无法理解在 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])

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

【问题讨论】:

标签: php python sockets network-programming


【解决方案1】:

php pack function 格式 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

【讨论】:

  • 我希望我能多次支持你。非常感谢。
  • 您能告诉我为什么选择 Q(unsigned long long) 代表 64 位整数和 L(unsigned long) 代表 32 位整数吗?我需要知道这一点,这样我才不会在做这些琐碎的事情时遇到麻烦。
  • 64 位是 8 个字节。 struct.pack format table 标题为“标准大小”的第三列显示了哪些格式对应于 8 个字节。 8 字节选项是qQd。由于我们需要无符号整数,Q 是正确的选择。同样,32 位是 4 字节。有四种选择,i,I,l,L。我假设 transaction_id 应该是未签名的,因此将选择范围缩小到IL。它们是等价的。任何一个都可以。
  • 谢谢。我不知道 unsigned long 和 unsigned int 是等价的。我想知道它们是否相同,那么为什么要使用不同的格式?
  • 我认为这与structhistorical connection to C有关。我从那里引用,“在许多情况下,有多种等效的方式来指定类型”。
【解决方案2】:

字节顺序在§7.3.2.1 of the library reference 中描述。大端封装的前缀为>

【讨论】:

  • sprunge.us/PBLf 是我的代码,但我没有返回相同的整数,而 PHP 代码工作得很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
  • 2012-04-23
  • 1970-01-01
相关资源
最近更新 更多