【问题标题】:Send double over local UNIX sockets通过本地 UNIX 套接字发送双倍
【发布时间】:2013-06-04 22:13:17
【问题描述】:

我正在尝试在两个 C++ 程序之间设置一个 UNIX 套接字服务器/客户端,遵循 Beejs Guide to UNIX IPC,但是示例代码仅演示了发送和接收 char 数组。我已经看到here 有人声称最好的选择是将双精度值转换为字符,但是因为我想在一秒钟内多次传递值,所以我想避免这种类型的转换。现在我正在尝试将指针传递给某个双精度,但我不知道如何获取另一侧的值。在我正在做的套接字客户端中:

...
double number = 453.23;
send(s, &number, sizeof(number), 0);

但我觉得这不是正确的方法。

【问题讨论】:

  • 这是否适用于跨平台应用程序?请记住,不同操作系统之间的字节序可能存在差异
  • 不,它只是一个Linux程序,要在同一台机器上运行。

标签: c++ sockets unix


【解决方案1】:

假设双方对doubles 有相同的表示(包括字节序),在套接字的另一端你可以做同样的事情:

double number;
recv(s, &number, sizeof(number), 0);

(当然假设您只是在传输doubles,或者您有某种协议,并且在程序的这一点上您确定发件人已经发送了您的double

如果不能保证字节序,那么您必须确定传输的字节序并适当地交换字节;最后,如果连 FP 类型的基本表示都不能保证,你最好的办法可能是把数字写成文本,做相关的sscanf/sprintf

【讨论】:

  • 究竟什么是endianess?我确定我发送doubles 的值几乎是硬编码到程序中的。另一方面,当使用简单的double 以外的数据结构时,同样的方法是否有效?以这种方式从 Eigen 库传递 VectorXd 对象时出现分段错误。
  • @joaocandre: en.wikipedia.org/wiki/Endianness;如果您仅在同一台机器上或同一架构的机器之间传递数据(例如 x86 & co.),您不必担心。对于其余部分,这种方法仅适用于 POD(“Plain Old Data”)类型,对于非 POD 类,您必须以某种方式将它们序列化并在另一端重新构建它们。
【解决方案2】:
  1. 如果“每秒几次”真的只是每秒“几次”(即几十甚至几百或几千)次,那么转换为 char 数组应该不会产生严重影响关于性能。

  2. 但无论如何您都不需要这种转换。如果您使用的是 IPC,那么这两个程序很可能在同一台机器上物理运行 - 如果您发送标量数据的原始内存表示,它将在接收端以相同的方式解释(这不适用于当然是指针)。除非您不想跨平台(即您不想在两种不同架构之间交换数据),否则不要担心正确的序列化。

【讨论】:

    【解决方案3】:

    通过套接字传输的信息没有您在编程语言中所理解的数据类型。 Char 数组本质上是字节数组(取决于 C 标准)。 见here for more info

    您可以传输您拥有的双精度,然后尝试从接收到的字节进行转换,或者您可以以某种方式对其进行序列化,然后进行反序列化。 如果您的应用程序由于实施或假设不佳而崩溃或出现未定义的行为,那么每秒几次都没有任何意义。

    当您通过套接字发送/接收数据时,请小心进行大量错误检查,因为假设是一切之母......

    恕我直言,将您的数据封装为 JSON、XML 或其他形式,以便双方准确了解正在传输的内容。

    编辑:如果您使用的是 IPC,您还不如设置一个共享内存?

    【讨论】:

    • 我现在正在 Unix IPC 上迈出第一步,只是为了在同一台机器上的两个进程之间共享数据。共享内存似乎需要更复杂的实现,这种方法有什么优势?
    • 它真的很简单。本质上,操作系统会分配一个内存文件,两个进程都可以对其进行读写。没有套接字、管道等。我相信这是在进程内进行通信的最快方式,但需要同步。
    【解决方案4】:

    我已经制作了一些发送二进制值的套接字程序:整数和双精度值,但为了做到这一点,您必须确定两台机器(服务器和客户端)都是二进制兼容的(字节顺序)。确保在两台机器中,双精度 (sizeof(double)) 的大小相同,均为 8 个字节。英特尔机器和平板电脑 Android 就是这种情况,它们在 C#、C++、Java 和 Delphi 中是相同的。我还在平板电脑(Android 和 Java)之间进行二进制传输到 Windows XP 和 7 中用 C# 编写的程序,它可以工作。

    请记住,它不可移植,应在移植到其他平台之前进行测试。

    我给你举几个例子:

    C++

    // Sender
    Send(socket, &MyDouble, sizeof(MyDouble), 0);
    
    // Reader
    Recv(socket, &MyDouble, sizefof(MyDouble), 0);
    

    Java:

    // Sender
    ByteBuffer buff = ByteBuffer.allocateDirect(8);
    buff.order(ByteOrder.LITTLE_ENDIAN); // To Intel machines
    buff.putDouble(MyDouble);
    Socket.getOutputStream().write(buff.array(), 0, 8);
    
    // Reader 
    byte[] data new byte[8];
    Socket.getInputStream().read (data, 0, 8);
    ByteBuffer buff = ByteBuffer.wrap(data);
    buff.order(ByteOrder.LITTLE_ENDIAN); // From Intel machines
    MyDouble = buff.getDouble();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-06
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 2015-05-27
      相关资源
      最近更新 更多