我正在使用字符串容器在C ++中开发一个程序,就像在std :: string中存储来自套接字的网络数据一样(这很好),我一次最多可以接收1452字节的数据帧,该协议使用包含有关数据包长度的数据区部分的信息的标头,并且标头是固定的20字节长度。我的问题是,一个字符串给了我一个未知的调试断言,因为它断言,但是我没有得到关于该字符串的消息。现在考虑到我可以在任何时间在帧中接收多个数据包,我将所有接收到的数据放入字符串中,将reinterpret_cast放入我的数据结构中,计算数据包的总长度,然后将数据包的数据部分复制到用于正则表达式处理的字符串,此时我执行string.erase,如mybuff.Erase(totalPackLen); <〜这就是调用assert,但是totalpacklen小于字符串大小。
我在这里缺少一些约定吗?或者std :: string真的是不合适的选择吗? TY。
我自己修复了它。使用几个C调用滚动我自己的非常简单的缓冲区:)
int ret = recv(socket,m_buff,0);
if(ret > 0)
{
BigBuff.append(m_buff,ret);
while(BigBuff.size() > 16){
Header *hdr = reinterpret_cast<Header*>(&BigBuff[0]);
if(ntohs(hdr->PackLen) <= BigBuff.size() - 20){
hdr->PackLen = ntohs(hdr->PackLen);
string lData;
lData.append(BigBuff.begin() + 20,BigBuff.begin() + 20 + hdr->PackLen);
Parse(lData); //regex parsing helper function
BigBuff.erase(hdr->PackLen + 20); //assert here when len is packlen is 235 and string len is 1458;
}
}
}
答案 0 :(得分:2)
从您提供的代码段中可以看出,您的数据包包含一个固定长度的二进制标头,后跟一个可变长度的ASCII字符串作为有效负载。你的第一个错误就在这里:
BigBuff.append(m_buff,ret);
这里至少有两个问题:
1.为什么追加?你可能已经发送了以前的任何消息。你应该从干净的石板开始
2.混合二进制和字符串数据可以工作,但通常不会。通常最好将二进制和ASCII数据分开。不要将std :: string用于非字符串数据。
追加将数据添加到字符串的末尾。追加后的下一个声明是对16的长度的测试,它告诉我你应该重新开始。同样,你可以重新解释BigBuff [0]中的强制转换:
Header *hdr = reinterpret_cast<Header*>(&BigBuff[0]);
由于您使用了append,因此您将永久处理收到的第一个数据包中的标头而不是当前数据包。最后,就是擦除:
BigBuff.erase(hdr->PackLen + 20);
这里有很多问题:
- 如果数据包长度和recv的返回值是一致的,则第一次调用将不执行任何操作(擦除处于但不超过字符串的结尾)。
- 如果数据包长度和recv的返回值不一致,则会出现问题。例如,这可能意味着需要多个物理帧来形成一个逻辑帧,这反过来意味着你需要回到原点。
- 假设物理和逻辑框架是同一个,你仍然会发现这一切都是错误的。如上所述,你第一次正在擦除任何东西。在循环开始时附加的内容正是您不想做的事情。
序列化通常是一个低级概念,最好这样处理。
答案 1 :(得分:0)
您的评论没有意义:
BigBuff.erase(hdr->PackLen + 20); //assert here when len is packlen is 235 and string len is 1458;
BigBuff.erase(hdr->PackLen + 20)
将从hdr->PackLen + 20
开始擦除,直到字符串结束。从代码的描述 - 在我看来,你正在删除超出内容数据的结尾。 Here's the reference for std::string::erase()
对你而言。
毋庸置疑std::string
在这里完全不合适,应该是std::vector
。