通过套接字传递记录

3

我已经在Python和Delphi代码之间建立了基本的套接字通信(仅文本)。现在,我想在双方之间发送/接收一组数据记录。我有一个“C兼容”的记录,并希望在Python中传递记录并以可用的格式访问它。

我使用conn.send("text") 在Python中发送文本,但是如何使用Python发送/接收缓冲区并访问发送的记录项?

记录

  TPacketData = record
    pID      : Integer;
    dataType : Integer;
    size     : Integer;
    value    : Double;
  end;

6
最好的办法是将记录序列化和反序列化为与语言无关的标准文本格式,如JSON和XML。您可以搜索类似于http://stackoverflow.com/search?q=%5Bdelphi%5D+%5Bjson%5D+serialize和同样适用于Python的查询主题来获取更多信息。 - Arioch 'The
通过Python套接字接收数据展示了如何接收数据。你只需要将1024更改为Delphi中Sizeof(TPacketData)的Python等效值,并读取到一个记录(在C中是结构体)。通过执行相反的操作,你可以将其发送回去。(而且没有必要使用JSON或XML来传输少量的二进制数据。对于少于50个字节的数值数据,序列化的开销太大了吧?) - Ken White
1
@Arioch,这是对于这个具体问题的过度工程化。双方都可以通过套接字读写二进制数据。 - OnTheFly
1
@user539484 JSON或XML消除了诸如字节序、浮点格式、结构布局等问题。 - David Heffernan
1
Python 的答案是“struct”标准库模块。 - Armin Rigo
显示剩余7条评论
2个回答

0

我知道这个答案有点晚了,但至少对于在搜索结果中找到这个问题的其他人可能会有用。因为你说Delphi代码发送和接收“C兼容数据”,所以就Python处理的答案而言,它似乎与另一端使用的是Delphi(或任何其他语言)无关...

Python的structsocket模块具有您描述的基本用法的所有功能。要发送示例记录,您可以执行以下操作。为简单起见,我假定了有符号整数和双精度浮点数,并将数据打包为“网络顺序”(大端)。这可以很容易地成为一行代码,但出于可读性和可重用性的考虑,我将其拆分为几行:

import struct
t_packet_struc = '>iiid'
t_packet_data = struct.pack(t_packet_struc, pid, data_type, size, value)
mysocket.sendall(t_packet_data)

当然,如果对格式字符串、数据准备等进行调整,就不需要进行上述“假设”。请参阅struct内联帮助以获取可能的格式字符串的描述 - 它甚至可以处理像Pascal-strings这样的东西... 顺便说一下,socket模块允许打包和解包一些网络特定的东西,而struct则不行,例如IP地址字符串(转换为它们的大端int-blob形式),并允许显式函数将数据从大端转换为本机字节序,反之亦然。为了完整起见,以下是如何在Python端解包上面打包的数据:

t_packet_size = struct.calcsize(t_packet_struc)
t_packet_data = mysocket.recv(t_packet_size)
(pid, data_type, size, value) = struct.unpack(t_packet_struc,
                                              t_packet_data)

我知道这在Python 2.x版本中有效,并且怀疑它在Python 3.x版本中也应该可以无需更改地工作。请注意一个重要的陷阱(因为很容易忽略,而且事后难以排除故障):除了不同的字节序外,您还可以根据如何前缀或不前缀格式字符串来区分使用“标准大小和对齐”(可移植)或使用“本机大小和对齐”(速度更快)打包东西。这些通常会产生与您预期大相径庭的结果,而不会给您任何提示原因...(有龙在其中)。


0

I don't know much about python, but I have done a lot between Delphi, C++, C# and Java even with COBOL.

Anyway, to send a record from Delphi to C first you need to pack the record at both ends,

in Deplhi

MyRecord = pack record

in C++

#pragma pack(1) 

I don’t know in python but I guess there must be a similar one. Make sure that at both sides the sizeof(MyRecord) is the same length.

Also, before sending the records, you should take care about byte ordering (you know, Little-Endian vs Big-Endian), use the Socket.htonl() and Socket.ntohl() in python and the equivalent in Deplhi which are in WinSock unit. Also a "double" in Delphi could not be the same as in python, in Delphi is 8 bytes check this as well, and change it to Single(4 bytes) or Extended (10 bytes) whichever matches. If all that match then you could send/receive binary records in one shut, otherwise, I'm afraid, you have to send the individual fields one by one.


1
我的主要问题是弄清楚如何在Python中编写记录或结构体的等效代码并进行发送/接收。我想我已经弄清了另一边的问题。 - runfastman
吹毛求疵的一点:packED recordpackED array是正确的Pascal术语;-P - Arioch 'The
1
@user1042067 为什么不直接使用 JSON 呢?考虑到网络通常比 CPU 慢,这不会造成太大问题,但会为以后更多的程序/语言提供更容易的集成。即使是协议扩展和添加新的额外字段,特别是后者 - 您的记录没有任何版本标记等。即使保持二进制,我也会尝试坚持可扩展的标准,如 EBML 或 XML/二进制,而不是无未来兼容性的临时死胡同。 - Arioch 'The
@user1042067 我怀疑不多的 Python 程序员了解 Pascal。试着用 C 术语或纯二进制布局来描述结构。 - Arioch 'The
1
这个问题使用JSON或类似的工具很容易解决。你还在等什么呢? - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接