在 C++ 中从服务器读取二进制数据时清除缓冲区

Clearing buffer while reading in binary data from a server in C++

我有一个服务器发送原始二进制数据来打印用户必须遍历的 "map",但是,我在读取每行后清除缓冲区时遇到问题,因此不断打印剩余数据在较短的行的末尾。在下面的屏幕截图中,您可以在左侧看到我的输出,在右侧可以看到 should 的输出。解决这个问题的最佳方法是什么?我觉得我错过了什么,但似乎找不到解决办法。

下面是 reading/printing 的代码:

char* mapData = NULL;
string command = "command> ";
size_t dataSize = 0;
while(mapData != command.c_str()) {
    unsigned char* buffer = (unsigned char*) &dataSize;
    connection = read(mySocket, buffer, 8);
    if(connection == -1 || connection < 0) {
        cerr << "**Error: could not read text size" << endl;
        return 1;
    }

    mapData = (char*)malloc(dataSize);
    buffer = (unsigned char*) mapData;

    while((connection = read(mySocket, buffer, dataSize)) != -1) {
        if(connection == -1 || connection < 0) {
            cerr << "**Error: could not read text size" << endl;
        return 1;
        }
        if(dataSize != 1) {
            cout << buffer;
        }
        free(buffer);
        buffer = NULL;
    }

}

您也应该清除缓冲区。添加:

 memset(mapData, 0, dataSize);

malloc.

之后

就像@eozd 指出的那样,在循环中调用mallocfree 是个坏主意,因为您使用了return 语句。您的代码可能会泄漏内存。您应该确保在 returns 之前调用 free。更好的是,您可以在 while loop 之外声明 buffer,并使用 break 而不是 return,如果出现错误 [=20],则调用 free =]

看你的解决方案,通信协议似乎涉及先发送数据大小,然后才是实际数据。数据大小如何写入线路?您可能需要从网络字节顺序转换它。

要调试,您可以在每次读取之前打印出 dataSize 的值,以确保它是您期望的值

您忽略了 read() 的 return 值以了解缓冲区中有多少字节。

read() returns 实际读取的字节数,可能比您请求的要少。所以你需要在循环中调用 read() 直到你读完所有你期望的字节,例如:

int readAll(int sock, void *buffer, size_t buflen)
{
    unsigned char* pbuf = reinterpret_cast<unsigned char*>(buffer);
    while (buflen > 0) {
        int numRead = read(sock, pbuf, buflen);
        if (numRead < 0) return -1;
        if (numRead == 0) return 0;
        pbuf += numRead;
        buflen -= numRead;
    }
    return 1;
}

此外,在读取缓冲区后,您将其视为以 null 结尾的,但事实并非如此,这就是为什么您的输出中会出现额外的垃圾。

更重要的是,mapData != command.c_str() 将始终为真,因此您的 while 循环会无限期地迭代(直到发生套接字错误),这不是您想要的。您希望在收到 "command> " 字符串时结束循环。

mapData 最初为 NULL,而 c_str() 永远不会 returns NULL,因此循环总是至少迭代一次。

然后您分配并释放 mapData 但不将其重置为 NULL,因此它仍指向无效内存。这并不重要,因为您的 while 循环只是比较指针。 c_str() 永远不会 return 指向 mapData 曾经指向的内存的指针。

要正确结束你的循环,你需要在阅读后比较mapData内容,而不是比较它的内存地址.

试试这个:

char *mapData = NULL;
uint64_t dataSize = 0;
const string command = "command> ";
bool keepLooping = true;

do {
    if (readAll(mySocket, &dataSize, sizeof(dataSize)) <= 0) {
        cerr << "**Error: could not read text size" << endl;
        return 1;
    }

    if (dataSize == 0)
        continue;

    mapData = new char[dataSize];

    if (readAll(mySocket, mapData, dataSize) <= 0) {
        cerr << "**Error: could not read text" << endl;
        delete[] mapData;
        return 1;
    }

    cout.write(mapData, dataSize);

    keepLooping = (dataSize != command.size()) || (strncmp(mapData, command.c_str(), command.size()) != 0);

    delete[] mapData;
}
while (keepLooping);

或者:

string mapData;
uint64_t dataSize = 0;
const string command = "command> ";

do {
    if (readAll(mySocket, &dataSize, sizeof(dataSize)) <= 0) {
        cerr << "**Error: could not read text size" << endl;
        return 1;
    }

    mapData.resize(dataSize);

    if (dataSize > 0) {
        if (readAll(mySocket, &mapData[0], dataSize) <= 0) {
            cerr << "**Error: could not read text" << endl;
            return 1;
        }

        cout << mapData;
    }
}
while (mapData != command);