Добрый день!
Сегодня тестировал клиент-сервер: с ноутбуком (клиент) отошел достаточно далеко от роутера - клиент повис, загрузив при этом весь процессор. В ходе непродолжительного дебага выяснилось, что клиент не успевает обработать все данные, первая партия приходит на обработку - 100 байт, за это время прилетает 200 байт, потом 400 и.т.д. Аналогичная ситуация на слабом железе, но тут все понятнее.
Вопрос по первому явлению, почему так? Из-за слабого канала скачет скорость передачи, за какой-то промежуток времени прилетает сразу много байт - и клиент виснет, правильно я понимаю?
И второй вопрос - как такое явление можно подавить или хотя бы минимизировать его влияние, ведь должны же быть какие-то стандартные приемы?
Немного про сервер: с сервера клиентам отсылается стабильным потоком 2КБ/с. Причем, если накапливаются 2 партии по 2КБ, то первая партия уже не нужна.
Код отправки:
C++ (Qt)
qint8 Server::slotSendData()
{
// Данные для отправки в сыром виде
QByteArray clientData = clientFiles[i].read();
// Вычисление размера отправляемых данных
qint16 sizeOfData = 2 * sizeof(qint16) + clientData.size();
// Формирование строки данных для отправки клиенту
data.clear();
// Байты 0 - 1: количество передаваемых байт
data.append(reinterpret_cast<char*>(&sizeOfData), sizeof(qint16));
// Байты 2 - 3: идентификатор элемента
data.append(reinterpret_cast<char*>(&i), sizeof(qint16));
// Данные из MMF
data.append(clientData);
tcpClients[i]->write(data);
return 0;
}
Код получения:
C++ (Qt)
qint8 Client::slotReadyRead()
{
QByteArray data;
QByteArray clientData;
qint16 sizeOfData = 0;
qint16 id = 0;
data.clear();
// Считывание пришедших данных
while (clientSocket->bytesAvailable())
{
data.append(clientSocket->readAll());
}
while (true)
{
if (data.size() < (qint16)sizeof(qint16))
break;
// Получение количества отправленных байт (0 - 1 байты)
memcpy(&sizeOfData, data.data(), sizeof(qint16));
if (data.size() < sizeOfData)
break;
// Получение id элемента (2 - 3 байты)
memcpy(&id, data.data() + sizeof(qint16), sizeof(qint16));
// Данные
clientData.clear();
clientData = data.mid(2 * sizeof(qint16), sizeOfData - 2 * sizeof(qint16));
// Передача данных элементу
emit signalSendDataToElement(id, clientData);
data = data.mid(sizeOfData);
}
return 0;
}
Вот на втором цикле при приемке данных и зависает программа.
Чуть не забыл! Отдельно хотелось бы спросить про первый цикл при приеме данных (увидел данную идею у М. Шлее), насколько он корректен и нужен ли вообще? Сам ставлю его под сомнение.