Очистка буфера при чтении двоичных данных с сервера в Stack Overflow

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

введите описание изображения здесь

И код, который читает / печатает это ниже:

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

}

0

Решение

Вы игнорируете возвращаемое значение 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, поэтому цикл ВСЕГДА повторяется хотя бы один раз.

Тогда вы выделяете и бесплатно 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);
2

Другие решения

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

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

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

1

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

 memset(mapData, 0, dataSize);

после malloc,

0