LINUX.ORG.RU

Qt сеть как принято обмениваться данными между клиентом и сервером

 , , ,


1

3

Добрый день.
Вот допустим есть клиент и сервер. Оба ра Qt. Между ними нужно сделать обмен сообщениями(в сообщениях должна быть структура вида ИМЯ ПАРАМЕТРА = ЗНАЧЕНИЕ, параметров каждый раз разное количество). Для сетевого взаимодействия будут использоваться классы Qt. Мне в голову приходит идея сделать объект класа QJsonDocument, перевести его в QByteArray, а затем писать в QTcpSocket(при этом можно еще контрольную сумму прикреплять), а с другой стороны делать обратную работу. А как бы делали вы? И еще вопрос: если на одном конце пишу в QTcpSocket, а на другом читаю, может ли случиться, что функция чтения вернет меньше байт чем было записано на другом конце, если да, то в каком случае?

★★★★★

Последнее исправление: rumgot (всего исправлений: 2)

qt головного мозга

при этом можно еще контрольную сумму прикреплять

зачем?

И еще вопрос: если на одном конце пишу в QTcpSocket, а на другом читаю, может ли случиться, что функция чтения вернет меньше байт чем было записано на другом конце, если да, то в каком случае?

Конечно может

Harald ★★★★★
()

Я бы использовал HTTP POST. Параметры можно передавать в формате application/x-www-form-urlencoded

Legioner ★★★★★
()

ИМЯ ПАРАМЕТРА = ЗНАЧЕНИЕ

typedef Param QPair<QString, QVariant>;
QList<Param> params = fillParams();

QDataStream s(&socket);
… // Все предварительные операции
s << params;
XMs ★★★★★
()

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

Конечно. Например, некоторые пакеты потерялись или идут с задержкой. Поэтому полезно вначале послать размер сообщения (заранее известен размер минимальной посылки), а потом просто ждать, пока в буфере не накопится нужное число байт

XMs ★★★★★
()

TCP - потоковый протокол. Нужно будет предусмотреть поиск конца сообщения, потому что:

а на другом читаю, может ли случиться, что функция чтения вернет меньше байт, если да, то в каком случае?

да, это может в любой момент произойти. А произойти это может из-за сети. Например в HTTP для этого используется заголовок Content-Length.

Если не требований, что каждое отправленное сообщение должно дойти и сами сообщения короткие, то можно посмотреть в сторону UDP. Эти пакеты целиком доходят (либо целиком не доходят, контрольная сумма там в конце пакета, пока операцинка не получит ее, то не проверит корректной пакета и соответственно приложению не отдаст). И повторную отправку через UDP тоже никто не запрещает сделать.

Добавлять своей контрольной суммы в сообщение при работе через TCP\UDP избыточно, оба этих протокола контролируют целостность передаваемых данных.

dvetutnev
()
Ответ на: комментарий от anonymous00

Причем протокол взаимодействия сложнее, чем просто обработка в браузере входящих событий с сервера

annulen ★★★★★
()
Ответ на: комментарий от annulen

Предрассудки. WebSockets — универсальный бинарный протокол прикладного уровня, без большого оверхеда. Зачем придумывать свой без веских причин и героически велосипедить?

anonymous00 ★★
()
Ответ на: комментарий от annulen

В TCP нужно реализовывать разбивание потока данных на сообщения, реализовать отправку сообщения частями (если хочется в процессе передачи большого куска данных отослать ещё что-то прямо сейчас). Конечно, это не полноценное мультиплексирование, но все эти примитивы уже есть в WebSockets.

но при этом требует навороченного хэндшейка

Он там примитивный и занимает меньше килобайта обычно.

anonymous00 ★★
()
Ответ на: комментарий от anonymous00

В TCP нужно реализовывать разбивание потока данных на сообщения

Вообще не проблема

реализовать отправку сообщения частями (если хочется в процессе передачи большого куска данных отослать ещё что-то прямо сейчас)

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

Он там примитивный и занимает меньше килобайта обычно.

Но для него придется тащить либу, тогда как для TCP хватит сисколлов

annulen ★★★★★
()

функция чтения вернет меньше байт чем было записано на другом конце, если да, то в каком случае?

Она еще и больше может вернуть.

cnupm
()
Ответ на: комментарий от rumgot

Подразумевается, что принимающая сторона знает, что ей пошлют. QDataStream позаботится о сериализации (и десериализации) Qt-классов, так что тут проблем быть не должно.

То, что вверху, не самый идеальный вариант для сети, поэтому имеет смысл сделать что-то вроде:

…
QByteArray arr;
quint32 size = 0;

QDataStream s(arr);
s << size;
s << params;

size = static_cast<quint32>(arr.size() - sizeof(size));
s.seek(0);
s << size;

socket.write(arr);

XMs ★★★★★
()
Последнее исправление: XMs (всего исправлений: 1)
Ответ на: комментарий от annulen

Ты не прав, WebSockets хорошая штука, и для задачи ТС-а прекрасно подойдет.

I-Love-Microsoft ★★★★★
()

Полезную я однако тему завёл.

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

Тебе нужен либо какой то протокол уже ориентированный на обмен сообщениями (http, web socket, stomp и т.п.) либо своя наколенная реализация. Что нужно для того, что бы json волшебным образом превращался в такой протокол, написано в теме на которую я дал линк :)

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)

Развивая предыдущее мнение, в Qt нету потокового парсера json, зато есть потоковый(sax) парсер xml.

pon4ik ★★★★★
()

А почему бы не писать просто и напрямую - через QDataStream? Тисипишный сокет - такой же QIODevice, как и файлы. В одном месте стрелочками затолкал, в другом месте - вытолкал. А если жсон - это еще парсить надо, зачем?

wolph ★★
()
Ответ на: комментарий от wolph

По сети так не выйдет. Очень возможна ситуация, что ты пошлёшь 4 байта, а придёт вначале два, потом один, а потом ещё один. Если делать «в лоб», у тебя десериализация объекта либо встанет до получения всех данных, либо извлечёт мусор (вглубь не лазил, как оно себя поведёт, не проверял, поэтому больше одного варианта). Поэтому имеет смысл вначале ждать, пока у тебя во входящем буфере накопится достаточное количество данных, а уже потом читать

XMs ★★★★★
()
Ответ на: комментарий от XMs

Почему? По идее десериализация или пройдет как надо, или вывалится по таймауту, разве не так? И все задержки уже скрыты внутри реализации QDataStream? Да и мусору откуда взяться, разве TCP не гарантирует что сообщение додет правильным, и никак иначе?

wolph ★★
()
Ответ на: комментарий от wolph

По идее десериализация или пройдет как надо, или вывалится по таймауту, разве не так?

Один из вариантов (как я писал выше, я не лазил глубоко в эту часть Qt, поэтому не уверен, как оно себя поведёт). Но даже в этом случае у тебя получается блок и, если оно выполняется в основном потоке, фриз всего.


разве TCP не гарантирует что сообщение додет правильным, и никак иначе?

Мусор может появиться, если блокирования до получения всех данных не произойдёт, и он возьмёт два байта вместо четырёх для, например, инта

XMs ★★★★★
()
Ответ на: комментарий от XMs

фриз всего.

Можно запихнуть в QtConcurrent::run к примеру.

На крайняк - можно просто по сети слать пару-тройку чисел (размер структуры, версия структуры (вдруг со временем поменяется), возможно какое магическое число, хотя не обязательно). А потом - просто кусок сырых байтов - утрамбовать этим датастримом все в qbytearray и слать его. Ну а на клиенте - получить размер, вытащить байтаррей целиком и уже там распотрошить его QDataStream'ом в обратную сторону.

wolph ★★
()

QTcpSocket

Это от незнания альтернатив или есть непреодолимое желание сделать всё вручную?

ya-betmen ★★★★★
()
Ответ на: комментарий от Harald

а веб-сервер на другой стороне кто писать будет?

Зачем писать? Сложно взять одну из миллиона реализаций? В этом и смысл HTTP — хорошие реализации что сервера, что клиента есть под все мыслимые и немыслимые платформы.

Legioner ★★★★★
()
Ответ на: комментарий от dvetutnev

Добавлять своей контрольной суммы в сообщение при работе через TCP\UDP избыточно, оба этих протокола контролируют целостность передаваемых данных.

Это не так. Контрольные суммы в TCP недостаточны на практике. Поэтому в любом протоколе поверх TCP лучше всего таки включать хорошую контрольную сумму. Или взять что-то вроде TLS, где целостность уже гораздо надёжней, помимо прочего есть и другие плюсы.

Legioner ★★★★★
()
Ответ на: комментарий от wolph

На крайняк - можно просто по сети слать пару-тройку чисел (размер структуры, версия структуры (вдруг со временем поменяется), возможно какое магическое число, хотя не обязательно). А потом - просто кусок сырых байтов - утрамбовать этим датастримом все в qbytearray и слать его

Ну, примерно так я в этом комменте и делал

XMs ★★★★★
()
Ответ на: комментарий от dvetutnev

Добавлять своей контрольной суммы в сообщение при работе через TCP\UDP избыточно, оба этих протокола контролируют целостность передаваемых данных.

Некоторые специалисты считают по другому: How both TCP and Ethernet checksums fail

cdslow ★★
()

И еще вопрос: если на одном конце пишу в QTcpSocket, а на другом читаю, может ли случиться, что функция чтения вернет меньше байт чем было записано на другом конце, если да, то в каком случае?

Возьми ZeroMQ и он это за тебя сделает.

А как бы делали вы?

Либо взял готовый вариант упаковщика, типа Google Protobuf, либо свой написал на memcpy, если хочу сам управлять упаковкой данных в сообщение.

Norgat ★★★★★
()
Ответ на: комментарий от Norgat

Хотелось бы обойтись средствами Qt.

rumgot ★★★★★
() автор топика
Ответ на: комментарий от ya-betmen

Изначально клиент подключается к серверу. Но далее может и сервер что-нибудь отправить.

rumgot ★★★★★
() автор топика
Ответ на: комментарий от rumgot

На чем будет сделана серверная часть? Если не выходить за рамки культей то вариант с вебсокетами будет самое то. Среди альтернатив zeromq и mqtt.

ya-betmen ★★★★★
()
Ответ на: комментарий от ya-betmen

Серверная тоже будет на Qt.

rumgot ★★★★★
() автор топика
1 февраля 2018 г.
Ответ на: комментарий от rumgot

А сегодняшняя это какая?

А по теме — описанное в ОП прямо-таки напрашивается на использование Google Protobuf. В сочетании с Qt получается немножко громоздко, но работает отлично.

hobbit ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.