QTcpSocket::write() — как гарантировать пересылку данных одним пакетом?

Добрый день.



Я новичек в сетевом программировании, но все же.



Пишу клиент-серверную систему. Есть qt клиент и qt сервер. Клиент отправляет запрос (json), сервер обрабатывает запрос и генерирует json ответ.



На стороне сервера отправка данных реализована через метод socket-> write(data), где data — это строка.



На стороне клиента при получении данных вызывается метод slotReadyRead(), подключенный к сигналу readyRead().



Данные считываются методом socket->readAll().



Но вот проблема, когда сервер передаёт небольшую строку, то клиент принимает ее полностью. Если большую строку (большой Джейсон), то строка передаётся частями. То есть один вызов сигнала readyRead не означает получение ПОЛНОГО сообщения от сервера, насколько я понимаю. Отсюда вопрос, как за один раз передать ВСЮ БОЛЬШУЮ строку?
  • Вопрос задан
  • 10742 просмотра
Пригласить эксперта
Ответы на вопрос 4
@AMDmi3
Никак. TCP — это поток данных, он не разбивается на сообщения. Когда нужны оные, передают сначала длину, потом тело каждого очередного сообщения.
Ответ написан
Комментировать
@rozhik
Никак. Есть такая штука, называется MTU . Пакет не может быть больше MTU в принципе (обычно это около полутора килобайт).
Вам в любом случае нужен протокол верхнего уровня, чтобы общаться сообщениями а не потоком (в принципе можно конечно скобочки считать, но это не решение). Часто между сообщениями бросают строку, которая гарантированно не может попасть в данных или передают перед сообщением размер.
Кпк начинающему я бы порекомендовал qtWebsocket.
Ответ написан
@rozhik
а она передастся не полностью, то что изменится?
изменится то, что Вы будете знать что данные еще не все пришли, и нужно читать еще.

Серьёзно — смотрите на кютивэбсокеты, они с потоками хорошо дружат и еще 100 плюсов есть. Я когда-то заманался бить студентов по руkам за кривые решения с raw-tcp.
Ответ написан
Берёте платформенно-независимый тип данных. К примеру quint64.
Вычисляете размер сообщения, сохраняете в quint64.
Отсылаете эту переменную, затем сообщение.

На другом конце:
if(bytesAvailable() < sizeof(quint64)) return;

Если больше, считываем quint64, в котором будет размер следующего сообщения. Ну и ждём, пока придут остальные байты, >= полученного значения.

И данные лучше сериализовать через QDataStream
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы