简体   繁体   English

C ++:如何通过UDP在结构中发送浮点数据并接收它?

[英]C++: How do we send float data in a structure, over UDP, and receive it?

This is my sender code snippet. 这是我的发件人代码段。

if(ThreadQ.try_dequeue(temp)){
            if(seqno>=2147483645)
            {
                seqno=-1;
            }
            if(frameno>=29)
            {
                frameno=-1;
            }
            seqno++;
            frameno++;
            fragno=0;
            std::ofstream f1("packet.txt",std::ios::app);
            for(int j=0;j<5;j++)
            {
                //Packetize-Fragment
                fp.fragno=j;
                fp.pl.line[0]=temp.line[k++];
                fp.pl.line[1]=temp.line[k++];
                fp.pl.line[2]=temp.line[k++];
                fp.pl.line[3]=temp.line[k++];
                fp.seqno = seqno;
                fp.frameno = frameno;                           
                retval = send(conn_socket, (char *)&fp, sizeof(fp), 0);
                for (i = 0; i < 4; i++)
                {
                    f1 << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch << "\n";                   
                }
            }
            f1 << "\n\n";
            k=0;
 }

and these are the relevant structures, 这些是相关的结构,

    typedef struct PacketPos{
        float x;
        float y;
        float z;
        int ch;     
    };

    typedef struct PacketPL2{
        PacketPos line[4];
    };
    typedef struct FinalPacket{
        PacketPL2 pl;
        int seqno;
        int frameno;
        int fragno;     
    };

But when I receive it at the receiver end, over UDP (Receiver code shown below): 但是,当我在接收器端通过UDP(如下所示的接收器代码)接收到它时:

char * Buffer = (char *)malloc(1000);
while (1){
        retval = recvfrom(msgsock, Buffer, 10000, 0, (struct sockaddr *)&from, &fromlen);
        printf("%d ", retval);
        fp = *(FinalPacket*)Buffer;
        std::ofstream fout("output.txt", std::ios::app);

        for (int i = 0; i < 4; i++)
        {
            fout << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch;
            fout << "\n";
        }
        fout << "\n\n";     
    }

the float data is not received and I just see 0s in the place of the float data. 浮点数据没有收到,我只是在浮点数据的位置看到0。 I'm a beginner, so can anyone tell me what I'm doing wrong here? 我是一个初学者,所以有人可以告诉我我在做什么错吗? Thanks in advance. 提前致谢。

I don't know the architecture where you are running. 我不知道您运行的架构。 I suppose it is x86 or 64 bits. 我想它是x86或64位。 The snippet you show is incomplete and there is at least one coding error. 您显示的代码段不完整,并且至少有一个编码错误。 First error, line is a vector of 4 elements: 第一个错误,线是4个元素的向量:

typedef struct PacketPL2 {
    PacketPos line[4];
};

In the client: 在客户端中:

fp.pl.line[0]=temp.line[k++];

k at some moment will be greater than 3 and you have a buffer overflow because you are setting k to 0 outside the loop. 某个时候k会大于3,并且您有缓冲区溢出,因为您在循环外将k设置为0。

I suppose conn_socket is already connected to the server, is it correct? 我想conn_socket已经连接到服务器了,对吗? Otherwise, there is another error. 否则,将出现另一个错误。

Other than this, your code should work alright. 除此之外,您的代码应该可以正常工作。

VERY IMPORTANT: YOUR CODE IS NOT PORTABLE AT ALL . 非常重要:您的代码根本不可携带 You must not just cast structures to buffers (and the other way around) if you want to make it portable. 如果要使结构可移植,则不能仅将结构强制转换为缓冲区(反之亦然)。 I'm talking about portability among different architectures: different int/float/double size and different endianship. 我说的是不同体系结构之间的可移植性:不同的int / float / double大小和不同的字节序。

For making it portable you need to define some endianship, floating point representation, and data size for your protocol. 为了使其可移植,您需要为协议定义一些字节序,浮点表示和数据大小。 Then make each conversion one piece of data at the time. 然后将每个转换一次转换为一个数据。 Using #pragma pack will help you only with data alignment in the structure but at the same time, not only it is compiler dependent but also is less efficient for the processor. 使用#pragma pack不仅可以帮助您进行结构中的数据对齐,而且同时,不仅依赖于编译器,而且对处理器的效率较低。

I implemented a UDP client-server with your code (but using sendto in the client), and except for the error above, it works OK. 我用您的代码实现了UDP客户端-服务器(但是在客户端中使用sendto),并且除上述错误外,它工作正常。 The code is not nice, I tried to put your snippets inside but it works. 该代码不是很好,我试图将您的代码片段放入其中,但是它可以工作。

Client: 客户:

typedef struct PacketPL2
{
    PacketPos line[4];
} s_pp2;
typedef struct FinalPacket
{
    PacketPL2 pl;
    int seqno;
    int frameno;
    int fragno;     
} s_fp;

int main()
{
    int seqno = 214000098;
    int frameno = 10;
    seqno++;
    frameno++;
    int fragno=0;
    s_fp fp;
    s_pp2 temp;
    int conn_socket;
    struct sockaddr_in servaddr;

    temp.line[0].x = 4.56;
    temp.line[0].z = 3.56;
    temp.line[1].x = 7.99;
    temp.line[1].z = 5.99;
    temp.line[2].x = 3.99;
    temp.line[2].z = 4.59;
    temp.line[3].x = 1.51;
    temp.line[3].z = 2.33;

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    servaddr.sin_port=htons(32000);

    conn_socket = socket(AF_INET, SOCK_DGRAM, 0);

    using namespace std;

    int k = 0;

    for(int j=0;j<5;j++)
    {
        //Packetize-Fragment
        fp.fragno=j;
        //ERROR, buffer overflow: WHEN K > 3 
        fp.pl.line[0]=temp.line[k++];
        fp.pl.line[1]=temp.line[k++];
        fp.pl.line[2]=temp.line[k++];
        fp.pl.line[3]=temp.line[k++];
        fp.seqno = seqno;
        fp.frameno = frameno;                           

//        int retval = send(conn_socket, (char *)&fp, sizeof(fp), 0);
        int retval = sendto(conn_socket,(char *)&fp, sizeof(fp),0, (struct sockaddr *)&servaddr,sizeof(servaddr));        

        cout << "RETVAL cli:" << retval << endl;

        for (int i = 0; i < 4; i++)
        {
            cout << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch << "\n";                   
        }
    }

    cout << "\n\n";

    //K IS INITIALIZED HERE
    k=0;

    return 0;
}

Server: 服务器:

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <strings.h>

typedef struct PacketPos
{
    float x;
    float y;
    float z;
    int ch;     
} s_pp;

typedef struct PacketPL2
{
    PacketPos line[4];
} s_pp2;
typedef struct FinalPacket
{
    PacketPL2 pl;
    int seqno;
    int frameno;
    int fragno;     
} s_fp;

int main()
{
    char * Buffer = (char *)malloc(1000);
    int msgsock;
    s_fp fp;
    struct sockaddr_in servaddr, from;
    socklen_t fromlen;

    bzero(&from, sizeof(from));
    bzero(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    servaddr.sin_port=htons(32000);


    msgsock = socket(AF_INET, SOCK_DGRAM, 0);
    bind(msgsock,(struct sockaddr *)&servaddr,sizeof(servaddr));


    using namespace std;

    while (1) 
    {
        int retval = recvfrom(msgsock, Buffer, 10000, 0, (struct sockaddr *)&from, &fromlen);
        cout << "RETVAL:" << retval << endl;

        fp = *(FinalPacket*)Buffer;

        for (int i = 0; i < 4; i++)
        {
            cout << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch;
            cout << "\n";
        }
        cout << "\n\n";     
    }

    return 0;
}

See these links for floating point representation and size: 有关浮点表示形式和大小,请参见以下链接:

What is the size of float and double in C and C++? C和C ++中float和double的大小是多少?

Fixed-size floating point types 固定大小的浮点类型

In your code : fp = *(FinalPacket*)Buffer will not be casted to Final Packet because sizeof(FinalPacket) is NOT what you expect. 在您的代码中: fp = *(FinalPacket*)Buffer不会被fp = *(FinalPacket*)Buffer转换为Final Packet因为sizeof(FinalPacket) 不是您所期望的。

For example: 例如:

Let's say we have a struct : 假设我们有一个struct

struct Point
{
 int x;
 int y;
}

Then sizeof(Point) is not 2 * sizeof(int) because of padding involved. 由于涉及到填充,因此sizeof(Point)不是2 * sizeof(int) Google for further info. 谷歌获取更多信息。

The solution to this is to use pragma pack 解决方案是使用pragma pack

So in your case, you should surround your struct with pragma pack. 因此,在您的情况下,应将结构用实用注释包包围。

Example: 例:

#pragma pack(push, 1)
typedef struct FinalPacket{
        PacketPL2 pl;
        int seqno;
        int frameno;
        int fragno;     
    };
#pragma pack(pop)

Now you will be able to cast the buffer directly to struct . 现在,您将能够castbuffer直接struct

Your question is easy to solve. 您的问题很容易解决。 I have wrote a simple test for udp communication. 我为udp通讯编写了一个简单的测试。 Now I give your my codes, only key points: 现在,我给出您的代码,只有关键点:

//my struct: 
struct TestCase
{
   float x;
   float y;
};

//client key points:
TestCase case_2;
case_2.x = 0.5;
case_2.y = 1.0;
if(-1 == sendto(sk_fd, (char*)&case_2, sizeof(case_2), 0, (struct sockaddr*)&remote, sizeof(remote)))
{
    cout << "client send data failed, error is " << strerror(errno) << endl;
    return 0;
}

//server key points:
TestCase server;
while(1)
{
    struct sockaddr_in client;
    memset(&server, 0, sizeof(server));
    socklen_t client_len = sizeof(client);
    const int result = recvfrom(sk_fd, &server, sizeof(server), 0, (struct sockaddr*)&client, &client_len);
    if(result < 0)
        cout << "server recv error is " << strerror(errno) << endl;
    cout << server.x << ' ' << server.y << endl;
    break;
}

After you see these above, I think you can know well. 看完以上这些,我想您会知道的。 You only need to change your code: char * Buffer = (char *)malloc(1000) . 您只需要更改代码: char * Buffer = (char *)malloc(1000) You should use the struct for receiving the data. 您应该使用该结构来接收数据。 Now Do you see it ? 现在你看到了吗? I hope this can help you. 希望对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM