我正在尝试移植一些 C 代码,但由于我尝试使用 ctypes 的 memcpy (没有工作),我真的陷入了困境。我希望找到一种使用 memcpy 等效功能的 python 方式
有任何想法吗
这是我尝试移植的 C 代码示例
i = l + 5;
t = htons(atoi(port));
memcpy((buf+i), &t, 2);
您几乎可以肯定不需要调用htons
然后将 2 个字节复制到缓冲区中 - 请参阅 Keith 的答案以了解原因。
但是,如果您确实需要这样做(也许您正在制作 IP 数据包以与捕获的有线数据包进行比较作为测试或其他东西?),您可以。
首先,如果您使用的是 a bytearray
(或任何其他符合可写缓冲区协议的东西),您只需使用普通的list
-style 切片分配:
# like C's memcpy(buf+i, foo, 2)
buf[i:i+2] = foo
你没有那个两字节的字符串foo
;你有一个短整数。在 C 语言中,您可以将其转换为指向两个字节的指针,只需使用&
运算符获取其地址,但 Python 无法做到这一点。幸运的是,有一个标准库模块struct
专门为这种事情而设计:
t = socket.htons(int(port))
buf[i:i+2] = struct.pack('h', t)
或者,因为struct
可以为您处理字节序:
t = int(port)
buf[i:i+2] = struct.pack('!h', t)
但是,通常您甚至不需要缓冲区复制;您可以在内部一次定义整个结构struct
。例如,如果您尝试将 IP 地址和端口打包到 6 字节数组中,您可以这样做:
buf = bytearray(6)
i = 0
addrbytes = [int(part) for part in addr.split('.')]
buf[i:i+4] = struct.pack('4B', addrbytes[0], addrbytes[1], addrbytes[2], addrbytes[3])
i += 4
portshort = int(port)
buf[i:i+2] = struct.pack('!h', portshort)
但这要简单得多:
addrbytes = [int(part) for part in addr.split('.')]
portshort = int(port)
buf = struct.pack('!4Bh', addrbytes[0], addrbytes[1], addrbytes[2], addrbytes[3], portshort)
我刚刚定义了一个按网络顺序排列的结构,四个字节后跟一个短字节,并将我的数据打包到其中。
最后要提到的一件事:如果你真的想使用 C 风格的代码来处理 C 风格的变量,ctypes模块是另一种选择。它是专门为与 C 代码交互而设计的,所以一般来说它是非常低级的(并且是标准库中唯一可以让您的代码段错误的模块),但它可以让您构建一些看起来更漂亮的中级东西像C:
class ADDRPORT(ctypes.BigEndianStructure):
_fields_ = [("addr", ctypes.c_char*4),
("port", ctypes.c_short)]
addrport = ADDRPORT(addrbytes, portshort)
由于您的 C 代码正在逐步填充缓冲区,而不是设置 a 的元素struct
,因此这可能不是您想要的。但值得注意的是,因为它可能会在某个时候成为你想要的。
看起来您正试图从用户输入或字符串中获取端口号。
在 Python 中:
port = int(port)
然后您可以将其直接传递给套接字实例:
socket = socket.socket(("127.0.0.1", port))
Pythonhtons
为您进行翻译。您只需将地址作为字符串和整数的元组提供给套接字(在 TCP 的情况下)。