首页 > 解决方案 > 协议缓冲区损坏数据

问题描述

这是我在这里的第一个问题,也是我自己的第一个项目。我有一个客户端(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

标签: c++socketssdkprotocol-buffers

解决方案


如果您查看 的原始十六进制值dWindDirection,它们是:

270:                     0x00 0x00 0x00 0x00 0x00 0xe0 0x70 0x40
1.2168372663711258e-309: 0x00 0x00 0x00 0x00 0x00 0xe0 0x00 0x00

因此,数据包的最后两个字节被设置为 0 而不是实际值。

听起来您的套接字读取代码可能有问题。我将首先使用Wireshark验证网络连接中的数据。如果那里正确,请在接收代码中设置断点并检查大小和缓冲区内容。


推荐阅读