在 C++ 中解析基于 TCP 的 TLV 协议时出现问题;

发布于 2024-12-13 04:51:09 字数 2253 浏览 1 评论 0原文

我正在尝试通过 TCP 实现 (T)LV 协议,从 python 客户端发送协议缓冲区并使用 C++ 服务器接收。

我的代码看起来或多或少像这样:

char* buffer[RCVBUFSIZE];
int recvsize= 0;
// Filling my buffer with as much as possible.
while(true) {
  if(recvsize == RCVBUFSIZE) {
    break;
  } else if(recvsize+= recv(sock, buffer+recvsize, sizeof(buffer)-recvsize, 0) < 1) {
    break;
  }
}
//Parsing LV protocol
while(true) {
  unsigned short protosize= 0;
  //Copy first two bytes into protosize
  memcpy((char *) &protosize, buffer, sizeof(unsigned short));
  if(protosize == 0) { break; } // Protocol indicates EOM be setting length to "0"
  void* protomsg[protosize];
  memcpy(protomsg, buffer+sizeof(unsigned short), protosize);
  int msglength= sizeof(unsigned short)+protosize;
  //Now I'll move the whole buffer to the left so that I don't have to keep track of where I'm at.
  memmove(buffer, buffer+msglength, RCVBUFSIZE-msglength);
  protoMsg pm;
  if(!pm.ParseFromArray(protomsg, protosize)) { break; } // Parsing failed.
  // Do stuff with parsed message.
}

现在我有几个问题:

  • 接收消息的 while 循环永远不会终止。我怀疑当不再有任何数据时,recv 调用会阻塞,而我预计它会返回错误。我找到了 select 函数来检查是否有东西可读。我会尝试一下。 但是,当我仅调用 receive 一次来跳过此问题时(收到的消息大约有 10 个字节,因此我希望在一次调用中收集所有消息。)我遇到另一个问题:
  • memcpy 和 memmove 似乎无法正常工作预期的。在第一个循环中,短路按预期进行处理(我收到的值与在另一端发送的值相同),但随后协议缓冲区解析的所有内容都失败了。我是否误解了什么?

编辑:关于 ntohs 的评论——我目前正在以小端方式传输短消息,忘了提及这一点。 (顺便说一句,我仍然会更改这一点。)

第三次编辑:代码现在可以工作,但我必须更改以下内容:

char* buffer[RCVBUFSIZE];
int recvsize= 0;
// Filling my buffer with as much as possible.
while(true) {
  if(recvsize == RCVBUFSIZE) {
    break;
  } else if((recvsize+= recv(sock, buffer+recvsize, sizeof(buffer)-recvsize, 0)) < 1) {
    break;
  } else if(recvsize > 1) {
    unsigned short msglength= 0;
    memcpy((char *) &msglength, buffer+recvsize-sizeof(unsigned short), sizeof(unsigned short));
    if(msglength == 0) { break; } // Received a full transmission.
  }
}

所以首先我需要在 recvsize+= recv() 周围添加括号 语句和第二个非阻塞方法由于某种原因不起作用,我现在正在检查在读取无符号短整型时传输的最后两个字节是否转换为 0。如果我偶然读取到不是长度字段的 0,这可能会导致问题。我可能会就此开始另一个问题。

我还将 protomsg 更改为 char[],但我认为这并没有真正改变任何东西。 (我已经解析了一个空数组..)

I am trying to implement a (T)LV protocol over TCP sending protocol buffers from a python client and receiving with a C++ server.

My code looks more or less like this:

char* buffer[RCVBUFSIZE];
int recvsize= 0;
// Filling my buffer with as much as possible.
while(true) {
  if(recvsize == RCVBUFSIZE) {
    break;
  } else if(recvsize+= recv(sock, buffer+recvsize, sizeof(buffer)-recvsize, 0) < 1) {
    break;
  }
}
//Parsing LV protocol
while(true) {
  unsigned short protosize= 0;
  //Copy first two bytes into protosize
  memcpy((char *) &protosize, buffer, sizeof(unsigned short));
  if(protosize == 0) { break; } // Protocol indicates EOM be setting length to "0"
  void* protomsg[protosize];
  memcpy(protomsg, buffer+sizeof(unsigned short), protosize);
  int msglength= sizeof(unsigned short)+protosize;
  //Now I'll move the whole buffer to the left so that I don't have to keep track of where I'm at.
  memmove(buffer, buffer+msglength, RCVBUFSIZE-msglength);
  protoMsg pm;
  if(!pm.ParseFromArray(protomsg, protosize)) { break; } // Parsing failed.
  // Do stuff with parsed message.
}

Now I have several problems:

  • The while loop receiving the message never terminates. I suspect that the recv call blocks when there isn't any data left anymore while I expected it to return with an error. I have found the select function to check whether there's something to read. I will give that a try.
    But when I call receive only once to skip this problem (The message received comes in at ~10 bytes, so I expect all to be collected in one call.) I get another problem:
  • memcpy and memmove don't seem to be working as expected. On the first loop the short is processed as expected (I receive the same value I send on the other side), but then everything from parsing of the protocol buffer fails. Have I misunderstood something?

Edit: Regarding the comment about ntohs -- I'm transmitting the short as little-endian currently, forgot to mention that. (I will change this still, btw.)

Third edit: The code now works, but I had to change the following:

char* buffer[RCVBUFSIZE];
int recvsize= 0;
// Filling my buffer with as much as possible.
while(true) {
  if(recvsize == RCVBUFSIZE) {
    break;
  } else if((recvsize+= recv(sock, buffer+recvsize, sizeof(buffer)-recvsize, 0)) < 1) {
    break;
  } else if(recvsize > 1) {
    unsigned short msglength= 0;
    memcpy((char *) &msglength, buffer+recvsize-sizeof(unsigned short), sizeof(unsigned short));
    if(msglength == 0) { break; } // Received a full transmission.
  }
}

So first I needed to add brackets around the recvsize+= recv() statement and second as the non-blocking method didn't work for some reason I am now checking whether the last two bytes that were transmitted translate to a 0 when read a unsigned short. This probably leads to a problem if I read a 0 by chance that is not the length field. I'll start another question about this probably.

I also changed protomsg to char[], but I don't think this really changed anything. (I had parsing working with a void array already.. )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凝望流年 2024-12-20 04:51:09

如果您收到的消息始终在 10 个字节左右,并且 RCVBUFSIZE 大于此值,那么您将永远不会终止,直到读取数据时出现错误。另外,代码中的 buffer 变量是一个 RCVBUFSIZE 指针数组,可能不是您想要的。

修改您的代码如下:

#define MINIMALMESSAGESIZE 10  // Or what the size may be
char buffer[RCVBUFSIZE];
int totalrecvsize= 0;
int recvsize= 0;
while(true) {
  if(totalrecvsize >= MINIMALMESSAGESIZE) {
    break;
  } else if(recvsize= recv(sock, buffer+totalrecvsize, sizeof(buffer)-totalrecvsize, 0) < 1) {
    break;
  } else {
    totalrecvsize += recvsize;
  }
}

If the message you receive is always around 10 bytes, and RCVBUFSIZE is more than that, you will never terminate until there is a error reading data. Also, the buffer variable in your code is an array of RCVBUFSIZE pointers, probably not what you want.

Modify your code as follows:

#define MINIMALMESSAGESIZE 10  // Or what the size may be
char buffer[RCVBUFSIZE];
int totalrecvsize= 0;
int recvsize= 0;
while(true) {
  if(totalrecvsize >= MINIMALMESSAGESIZE) {
    break;
  } else if(recvsize= recv(sock, buffer+totalrecvsize, sizeof(buffer)-totalrecvsize, 0) < 1) {
    break;
  } else {
    totalrecvsize += recvsize;
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文