Очистка буфера при чтении двоичных данных с сервера в C ++ - PullRequest
0 голосов
/ 24 ноября 2018

У меня есть сервер, который отправляет необработанные двоичные данные для распечатки «карты», через которую должен пройти пользователь, однако у меня возникают проблемы с очисткой буфера после каждого чтения строки и, таким образом, продолжают выводить остаточные данные в концеболее короткие линии.На скриншоте ниже вы можете видеть мой вывод слева, и что вывод должен быть справа.Каков наилучший способ решить эту проблему?Я чувствую, что что-то упустил, но не могу найти решение.

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

}

Ответы [ 3 ]

0 голосов
/ 24 ноября 2018

, как указывал @eozd, вызывать malloc и free в вашем цикле - плохая идея, так как вы используете операторы return.Ваш код может утечь память.Вы должны убедиться, что вы звоните free до возвращения.Более того, вы можете объявить свой buffer вне while loop, и использовать break вместо return, и вызвать free, если произошла ошибка EN

Глядя на ваше решение, кажется,что протокол связи включает в себя сначала отправку данных, а затем фактические данные.Как размер данных записывается в провод?Вам может потребоваться преобразовать его из сетевого порядка байтов.

Для отладки вы можете распечатать значение dataSize перед каждым чтением, чтобы убедиться, что это то, что вы ожидаете

0 голосов
/ 24 ноября 2018

Вы игнорируете возвращаемое значение 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;
}

Кроме того, после чтения буфера вы рассматриваете его как нулевойопределяется, но это не так, поэтому вы получаете дополнительный мусор в выводе.

Что еще более важно, mapData != command.c_str() всегда будет верным, поэтому ваш цикл while будет повторяться бесконечно (пока не произойдет ошибка сокета), что не то, что вы хотите.Вы хотите, чтобы цикл завершился, когда вы получите вместо него строку "command> ".

mapData изначально имеет значение NULL, а c_str() НИКОГДА не возвращает NULL, поэтому цикл ALWAYS повторяется хотя бы один раз.

Затем вы выделяете и освобождаете 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);
0 голосов
/ 24 ноября 2018

Вы должны очистить буфер тоже.Добавить:

 memset(mapData, 0, dataSize);

после malloc.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...