这是我的发件人代码段。
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。我是初学者,所以有谁能告诉我这里我做错了什么?提前谢谢。
答案 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;
}
请参阅以下链接了解浮点表示和大小:
答案 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来接收数据。你看到了吗?我希望这可以帮到你。