通过 TCP/IP 以太网发送数字数据

Posted

技术标签:

【中文标题】通过 TCP/IP 以太网发送数字数据【英文标题】:Send numerical data via TCP/IP ethernet 【发布时间】:2014-04-29 21:47:01 【问题描述】:

所以我知道你们中的许多人会反对这样做,但我想通过 TCP/IP 将浮点数发送到在 SoC 上运行的 TCP 服务器(Zynq7020,服务器在 Arm A9 上)。在继续使用可能更适合发送原始数据的 UDP 之前,我想让它作为一个简单的概念证明工作。我在客户端将浮点数转换为 char 数组并在服务器上再次转换时遇到问题。虽然我不确定这是最好的方法。

我正在使用 WinSocket API,并且正在发送数据(尽管我不确定这是否正确或有效!):

char * sendbuf;
sendbuf = reinterpret_cast<char *>(f);
iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0);

基本上这是正确的,并且不使用 UDP,通过 TCP 浮动的最佳方式是什么。我猜解码本质上是对用于将浮点数发送为 char* 的方法进行逆向工程。

---下面是通过 WinSock 将浮点数发送到 Zynq ARM cpu LwIP 的完整工作示例--

主机 Windows 7(可能使用 htonf,但我使用的是 x86,所以没有字节序问题):

int FPGA_Accelerator::sendFloat(float* f) 
    char *sendbuf;
    int iResult;
    char arr[4];

    *(float*)arr= *f;

    printf("Sending "); printf(arr); printf("\n");
    iResult = send(connection, arr, (int) sizeof(arr), 0);
    if (iResult == SOCKET_ERROR) 
    printf("send failed: %d\n", WSAGetLastError());
    closesocket(connection);
    WSACleanup();
    return -1;
    

    printf("Bytes Sent: %ld\n", iResult);

    return 1;
;

Zynq 代码。在 recv_callback 中我调用函数parse_input(p-&gt;payload)

void parse_input(char* input)
    xil_printf("Input : ");
    xil_printf(input);
    xil_printf("\n\r");

u32 d = *(u32*)input;
union v
    float f;
    u32 u;
;
union v val;
val.u = d;

printf("Value u32 = %i \n\r",val.u);
printf("Value float = %f \n\r",val.f);


【问题讨论】:

«UDP 这可能更适合发送原始数据。»这不是真的。 UDP/TCP 与数据的原始性无关。在这两种情况下,如果您需要发送相同的浮点数,则必须使用相同的编码:) 我会阅读一些有关 ASN.1 的信息,如果您的数据变得更复杂,它可能会有所帮助 C 不是 C++。它们仍然不一样。 【参考方案1】:

无论你发送的是浮点数还是字符串。您将数据作为字节数组发送并在另一端接收它们并按照您的意愿解释它们。因此,在您的情况下,您应该发送一个 4 字节长的浮点数。您应该发送 4 个字节作为字节数组,然后将其转换为浮点数并使用它。

iResult = send(ConnectSocket, (char*)&f, (int) sizeof(float), 0);

在接收器部分:

char *receivebuf;
// read data from socket
float *receivedFloat = (float*)receivebuf;

使用 UDP 更容易,因为您不必检查连接和发送数据是否成功。您只需发送它而不连接到服务器。

【讨论】:

【参考方案2】:

这不是 TCP 与 UDP 的问题。

首先,要发送单个浮点值,不要将其重新解释为地址,而是取浮点数的地址

iResult = send(ConnectSocket, &f, (int) sizeof(f), 0);

但这只有在通信两端具有相同架构的情况下才有效。

为了使其独立于架构问题,您必须使用一些External Data Representation 来进行从一个系统到另一个系统的传输。或者,您也可以使用基于文本的协议并将浮点值转换为字符串。

【讨论】:

htonf(f) 应该足以满足 OP 的情况。我没有看到将f 转换为字符串的好处 这是错误的。如果ffloat 或指向float 的指针,strlen(f) 毫无意义。 @DavidSchwartz 谢谢,已修复。 @RedAlert,正如你所说,我需要使用 htonf,但我运行的是 Windows 7,它不在 WinSock API 中,(我无法调用该函数,并且在 WinSock API 页面上它指出htonf 需要 Windows 8 最低要求)还有其他选择吗? @SamPalmer 您不必专门使用htonfhtonl() 将为您转换任何 32 位输入,因此您可以使用它。请注意,在接收端,您必须使用ntohl() 才能认为它有效。【参考方案3】:

这是不正确的。顾名思义,strlen 用于字符串。您需要将缓冲区的实际大小传递给send

【讨论】:

我给出的示例(以及使用发送方法,而不是强制转换)是正确的,是从 MSDN WinSocket 示例直接复制的。

以上是关于通过 TCP/IP 以太网发送数字数据的主要内容,如果未能解决你的问题,请参考以下文章

TCP/IP||链路层

TCP/IP——链路层

[TCP/IP详解卷1:协议] Chapter2.链路层

TCP/IP Over USB 用USB传输以太网数据,给你的MCU加个网卡

网络基础tcp/ip协议三

TCP/IP详解 学习四