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

标签 c++ server binary-data datareader

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

enter image description here

读取/打印的代码如下:

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;
    }

}

最佳答案

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

read() 返回已读取的实际字节数,这可能比您请求的要少。所以你需要在循环中调用 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() 永远不会返回 NULL,因此循环总是至少迭代一次。

然后您分配并释放 mapData 但不将其重置为 NULL,因此它仍指向无效内存。这并不重要,因为您的 while 循环只是比较指针。 c_str() 永远不会返回指向 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);

关于c++ - 在 C++ 中从服务器读取二进制数据时清除缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53459312/

相关文章:

mysql - 服务器响应时间过长,优化Laravel项目?

java - 如何使用 Java 访问 MySQL 中的特定行

Python将一个long int作为二进制值写入文件

c# - 通过二进制文件可以看到源代码吗? (C#)

c++ - 为什么这个程序不能从 .bin 文件中正确读取(或写入?)? (C++)

c++ - 我可以让 gcc 链接器创建一个静态库吗?

c++ - "Interface"类似于 boost::bind 的语义

c++ - 如何在不复制的情况下将 std::string 的一部分放入 Streambuf 中?

c++ - 没有 MFC 的 VC++ 中的 ActiveX?

路由的 REST API 最佳实践