如何在Poco C++中复制缓冲区字节块?

4

你好,我正在尝试使用Poco编写TCP连接。客户端发送了一个包含以下字段的数据包:

packetSize : int date : int ID : int

因此,前4个字节包含数据包大小。在接收端,我有以下代码:

int packetSize = 0;
char *bufferHeader = new char[4];

// receive 4 bytes that contains packetsize here
socket().receiveBytes(bufferHeader, sizeof(bufferHeader), MSG_WAITALL);

Poco::MemoryInputStream *inStreamHeader = new Poco::MemoryInputStream(bufferHeader, sizeof(bufferHeader));
Poco::BinaryReader *BinaryReaderHeader = new Poco::BinaryReader(*inStreamHeader);

(*BinaryReaderHeader) >> packetSize; // now we have the full packet size

现在我正在尝试将所有剩余的输入字节存储到一个数组中,以备将来进行二进制读取:

int ID = 0;
int date = 0;
int availableBytes = 0;
int readedBytes = 0;
char *body = new char[packetSize - 4];

do
{
    char *bytes = new char[packetSize - 4];

    availableBytes = socket().receiveBytes(bytes, sizeof(bytes), MSG_WAITALL);

    if (availableBytes == 0)
        break;

    memcpy(body + readedBytes, bytes, availableBytes);

    readedBytes += availableBytes;

} while (availableBytes > 0);

Poco::MemoryInputStream *inStream = new Poco::MemoryInputStream(body, sizeof(body));
Poco::BinaryReader *BinaryReader = new Poco::BinaryReader(*inStream);

(*BinaryReader) >> date;
(*BinaryReader) >> ID;

cout << "date :" << date << endl;
cout << "ID :" << ID << endl;

问题在于正文的字节块没有存储剩余的字节,它总是只有前4个字节(日期)。因此,在输出中,日期是正确的,但是ID不符合预期。我尝试了流式传输而没有块复制,并手动接收每个字段而不使用循环,结果很好,数据也如预期。但当我试图将传入的字节存储到一个数组中,然后将该数组传递给MemoryStream以读取它时,我只有第一个块是正确的且符合预期!
我真的需要将所有传入的字节存储到一个数组中,然后读取整个数组,我应该如何更改我的代码?
非常感谢。
1个回答

1

我看到你的代码中有两个错误。或者更准确地说,你犯了同样的一个错误两次。

你混淆了char[]sizeofchar *sizeof;第一个是数组中字符的数量,第二个是指针的大小:通常是4或8个字节,取决于内存模型。

所以,当你写下:

availableBytes = socket().receiveBytes(bytes, sizeof(bytes), MSG_WAITALL);

你正在请求4个字节(我猜),这并不严重,因为你会继续请求其他字节直到消息结束。
真正的问题在于以下指令。
Poco::MemoryInputStream *inStream = new Poco::MemoryInputStream(body, sizeof(body));

inStream 中只传输 sizeof(char *) 字节。

你应该将 sizeof(body)sizeof(bytes) 替换为 packetSize - 4

P.s.:抱歉我的英语不好。

编辑:我发现另一个错误。在这个指令中。

 char *bytes = new char[packetSize - 4];

你分配了 packetSize - 4 个字符的内存。这段内存从未被删除,且是在 do ... while() 循环中分配的。

你可以在循环外分配 bytes(与 body 一起)。

编辑 2016.03.17

建议解决方案(注意:未经测试)

size_t  toRead  = packetSize - 4U;
size_t  totRead = 0U;
size_t  nowRead;

char * body = new char[toRead];

do 
{
  nowRead += socket().receiveBytes(body+totRead, toRead-totRead,
                MSG_WAITALL);

  if ( 0 == nowRead )
     throw std::runtime_error("shutdown from receiveBytes()");

  totRead += nowRead;

} while ( totRead < toRead );

Poco::MemoryInputStream *inStream = new Poco::MemoryInputStream(body, 
                                           toRead);

delete[] body;

body = NULL;

谢谢您的回复。是的,我对此感到困惑,毕竟当我将char *更改为char []时,我可以得到完整的数据包。但实际上,当我尝试考虑缓冲区的packetSize时,我无法调整Char []的大小,事实上,C++不接受它作为数组大小的常量值,但它接受它作为:char * buffer = new char [packetSize],而当我使用char *时,每次只能获取4个字节而不是整个数据包。我该如何解决这个问题? - AmirHasan Hesam
@AmirHasanHesam:我认为你应该避免使用sizeof()这种方式;你已经知道了期望的字节数: 利用它。而且你可以只使用一个缓冲区。我将编辑我的答案,展示一种可能的解决方案。 - max66

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接