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

时间:2015-06-25 06:41:33

标签: c++ sockets network-programming udp type-conversion

这是我的发件人代码段。

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;
 }

这些是相关的结构,

    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;     
    };

但是当我在接收端收到它时,通过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";     
    }

没有接收浮点数据,我只是在浮点数据的位置看到0。我是初学者,所以有谁能告诉我这里我做错了什么?提前谢谢。

3 个答案:

答案 0 :(得分:1)

我不知道您正在运行的架构。我想它是x86或64位。 您显示的代码段不完整,至少有一个编码错误。 第一个错误,line是4个元素的向量:

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

在客户端:

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

k在某个时刻将大于3并且您有缓冲区溢出,因为您在循环外将k设置为0.

我想conn_socket已经连接到服务器了,是不是正确?否则,还有另一个错误。

除此之外,您的代码应该正常工作。

非常重要:您的所有代码都不是便携式的。如果要使结构可移植,则不能只将结构转换为缓冲区(反之亦然)。我在谈论不同架构之间的可移植性:不同的int / float / double大小和不同的endianship。

为了使其可移植,您需要为协议定义一些endianship,浮点表示和数据大小。然后每次转换一个数据。使用#pragma pack只能帮助您在结构中进行数据对齐,但同时,它不仅依赖于编译器,而且对处理器的效率也较低。

我用你的代码实现了一个UDP客户端服务器(但在客户端使用了sendto),除了上面的错误,它工作正常。代码不是很好,我试图把你的片段放在里面,但是它有效。

客户端:

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;
}

服务器:

#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;
}

请参阅以下链接了解浮点表示和大小:

What is the size of float and double in C and C++?

Fixed-size floating point types

答案 1 :(得分:0)

在您的代码中:fp = *(FinalPacket*)Buffer不会投放到Final Packet,因为sizeof(FinalPacket) 您的期望。

例如:

我们说我们有struct

struct Point
{
 int x;
 int y;
}

由于涉及填充,sizeof(Point)不是2 * sizeof(int)。谷歌了解更多信息。

解决方法是使用pragma pack

所以在你的情况下,你应该使用pragma pack包围你的结构。

示例:

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

现在,您可以cast buffer直接struct

答案 2 :(得分:0)

您的问题很容易解决。我为udp通信写了一个简单的测试。现在我给出你的代码,只有关键点:

//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;
}

看到上述内容后,我想你可以很清楚。您只需要更改代码:char * Buffer = (char *)malloc(1000)。您应该使用struct来接收数据。你看到了吗?我希望这可以帮到你。