c++ - 协议缓冲区损坏数据
问题描述
这是我在这里的第一个问题,也是我自己的第一个项目。我有一个客户端(Windows 10 上的 C++),它使用 SimConnect SDK 从 Prepar3D Flight Simulator 和一个接收该数据的服务器(Ubuntu 上的 C)中提取数据。我正在使用套接字和协议缓冲区。客户端从 sim 接收数据,将其映射到协议缓冲区并发送。服务器从套接字接收它,解码协议缓冲区,然后处理它。问题是最后一个字段 (dWindDirection) 在接收端总是损坏。我不完全确定它是如何/为什么被破坏的,但它是一致的,因为在套接字的相同输入中总是会导致来自套接字的相同的损坏输出。我在 C++ 中通过套接字遵循协议缓冲区用于在套接字上使用协议缓冲区。我在下面包含了我的代码以及输出。
源代码也可以在这里找到。https://github.com/nbreen/Simconnect-Data-Client
发送 protobuff 的客户端函数
DWORD WINAPI createProto(LPVOID lParam) {
ObjectData* toConvert = (ObjectData*)lParam;
fopen_s(&dataOut,"dataOut.txt", "a+");
fprintf(dataOut, "Before serialiing \n");
logData(toConvert);
simConnect::simData convertedData;
std::string toStr(toConvert->szTitle);
convertedData.set_sztitle(toStr);
convertedData.set_dabsolutetime(toConvert->dAbsoluteTime);
convertedData.set_dtime(toConvert->dTime);
convertedData.set_usimonground(toConvert->uSimOnGround);
convertedData.set_daltitude(toConvert->dAltitude);
convertedData.set_dheading(toConvert->dHeading);
convertedData.set_dspeed(toConvert->dSpeed);
convertedData.set_dverticalspeed(toConvert->dVerticalSpeed);
convertedData.set_dgpseta(toConvert->dGpsEta);
convertedData.set_dlatitude(toConvert->dLatitude);
convertedData.set_dlongitude(toConvert->dLongitude);
convertedData.set_dsimtime(toConvert->dSimTime);
convertedData.set_dtemperature(toConvert->dTemperature);
convertedData.set_dairpressure(toConvert->dPressure);
convertedData.set_dwindvelocity(toConvert->dWindVelocity);
convertedData.set_dwinddirection(toConvert->dWindDirection);
printf("Size after serializing is %ld\n", convertedData.ByteSizeLong());
long pktSize = convertedData.ByteSizeLong();
fprintf(dataOut, "After serializing before socket\n%s\n\n", convertedData.DebugString().c_str());
char* pkt = new char[pktSize];
google::protobuf::io::ArrayOutputStream aos(pkt, pktSize);
google::protobuf::io::CodedOutputStream* coded_pkt = new google::protobuf::io::CodedOutputStream(&aos);
coded_pkt->WriteVarint64(convertedData.ByteSizeLong());
convertedData.SerializeToCodedStream(coded_pkt);
int iResult = send(clientSocket, pkt, pktSize, 0);
printf("Sent bytes %d\n", iResult);
fclose(dataOut);
return 0;
}
接收和处理 protobuff 的服务器函数
while(1) {
result = recv(client, sizeBuff, 4, MSG_PEEK);
printf("Receive is %d\n", result);
if (result == -1) {
printf("Error receiving data with byteSize\n");
break;
}else if (result == 0) {
break;
}
if (result > 0) {
printf("First read byte count is %d\n", result);
readMessage(client, readHeader(sizeBuff));
}
}
google::protobuf::uint64 readHeader(char *buf) {
google::protobuf::uint64 size;
google::protobuf::io::ArrayInputStream ais(buf,4);
google::protobuf::io::CodedInputStream coded_input(&ais);
coded_input.ReadVarint64(&size);//Decode the HDR and get the size
std::cout<<"size of payload is "<<size<<std::endl;
return size;
}
void readMessage(int csock, google::protobuf::uint64 siz) {
int bytecount;
simConnect::simData payload;
char buffer [siz+4];//size of the payload and hdr
//Read the entire buffer including the hdr
if((bytecount = recv(csock, (void *)buffer, 4+siz, 0))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
}
std::cout<<"Second read byte count is "<<bytecount<<std::endl;
//Assign ArrayInputStream with enough memory
google::protobuf::io::ArrayInputStream ais(buffer,siz+4);
google::protobuf::io::CodedInputStream coded_input(&ais);
//Read an unsigned integer with Varint encoding, truncating to 32 bits.
coded_input.ReadVarint64(&siz);
//After the message's length is read, PushLimit() is used to prevent the CodedInputStream
//from reading beyond that length.Limits are used when parsing length-delimited
//embedded messages
google::protobuf::io::CodedInputStream::Limit msgLimit = coded_input.PushLimit(siz);
//De-Serialize
payload.ParseFromCodedStream(&coded_input);
//Once the embedded message has been parsed, PopLimit() is called to undo the limit
coded_input.PopLimit(msgLimit);
//Print the message
//std::cout<<"Message is "<<payload.DebugString();
FILE *outFile = fopen("out.txt", "a+");
/*std::string strPkt(buffer);
payload.ParseFromString(strPkt);*/
fprintf(outFile, "From socket\n%s\n\n", payload.DebugString().c_str());
fclose(outFile);
cudaProcess(payload);
}
客户端输出
Before serialiing
Title: F-22 Raptor - 525th Fighter Squadron
Absolute Time: 63631767652.278290 seconds
Zulu Time: 68452.281250 Seconds
Sim On Ground: 0
Altitude: 11842.285630 Feet
Heading: 3.627703 Radians
Speed: 426.008209 Knots
Vertical Speed: 596.607849 Feet Per Second
GPS ETA: 0.000000 Seconds
Latitude: 30.454685 Degrees
Longitude: -86.525197 Degrees
Sim Time: 2996.388142 Seconds
Temperature: -8.145923 Celsius
Air Pressure: 648.718994 Millibars
Wind Velocity: 36.988354 Feet Per Second
Wind Direction: 270.000000 Degrees
After serializing before socket
szTitle: "F-22 Raptor - 525th Fighter Squadron"
dAbsoluteTime: 63631767652.27829
dTime: 68452.28125
usimOnGround: 0
dAltitude: 11842.285629708613
dHeading: 3.6277025313026936
dSpeed: 426.00820922851562
dVerticalSpeed: 596.60784912109375
dGpsEta: 0
dLatitude: 30.454685493870045
dLongitude: -86.525197127202063
dSimTime: 2996.388142343636
dTemperature: -8.1459226608276367
dAirPressure: 648.718994140625
dWindVelocity: 36.988353729248047
dWindDirection: 270
服务器输出
From socket
szTitle: "F-22 Raptor - 525th Fighter Squadron"
dAbsoluteTime: 63631767652.27829
dTime: 68452.28125
usimOnGround: 0
dAltitude: 11842.285629708613
dHeading: 3.6277025313026936
dSpeed: 426.00820922851562
dVerticalSpeed: 596.60784912109375
dGpsEta: 0
dLatitude: 30.454685493870045
dLongitude: -86.525197127202063
dSimTime: 2996.388142343636
dTemperature: -8.1459226608276367
dAirPressure: 648.718994140625
dWindVelocity: 36.988353729248047
dWindDirection: 1.2168372663711258e-309 <-- This is always the corrupt value when Wind direction is 270
解决方案
如果您查看 的原始十六进制值dWindDirection
,它们是:
270: 0x00 0x00 0x00 0x00 0x00 0xe0 0x70 0x40
1.2168372663711258e-309: 0x00 0x00 0x00 0x00 0x00 0xe0 0x00 0x00
因此,数据包的最后两个字节被设置为 0 而不是实际值。
听起来您的套接字读取代码可能有问题。我将首先使用Wireshark验证网络连接中的数据。如果那里正确,请在接收代码中设置断点并检查大小和缓冲区内容。
推荐阅读
- python - Matplotlib set axis limits works in __init__ but not on button click?
- ruby-on-rails - 使用 axlsx gem 将数组导出到 xlsx
- lua - 加载 Lua 函数块,用沙盒修改 5.2 中的环境
- excel - Excel 公式将日期作为标志 (1,0) 获取从现在到过去 1 年的月份。如过去 3 个月、过去 6 个月和年初至今
- ios - iOS:如何将应用程序的所有 ImageView 的“accessibilityIgnoresInvertColors”设置为 true?
- android - How to get first letter of string in flutter dart?
- spring - 如何在回调前添加 /**/ 创建 JSONP 过滤器?
- android - ImageViewHolder.getAdapterPosition() / .getLayoutPosition() 不起作用
- python - 为什么我的碰撞测试总是返回“真”,为什么图像矩形的位置总是错误 (0, 0)?
- python - 如何将正十进制 int 转换为十六进制字符串?