Название: Чтение с сокета без QDataStream Отправлено: Fregloin от Апрель 28, 2011, 14:48 Как читать с сокета данные без QDataStream (который используется во всех примерах).
Есть сервер (написан на нативных сокетах под QNX), пишу клиент под Win/Lin под Qt. Нужно получать с сервера пакеты (пакеты могут иметь разную длину). Пакет представляет из себя несколько массивов собранных в кучу друг за другом (типы quin32, структуры и т.п.). при сигнале readyRead() получаю только часть данных (меньше чем нужно в bytesAvailable()). при socket->read() я так понимаю внутренний буфер очищается на колчиество считанных байт. Как грамотно реализовать чтение? я пока делаю так: Код: void QClient::readyRead() Название: Re: Чтение с сокета без QDataStream Отправлено: RedDog от Апрель 28, 2011, 15:19 Код: QByteArray arr; // где нидь глобально (всмысле как закрытый член класса) Код: arr.append(socket->readAll()); Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Апрель 28, 2011, 15:22 а без QByteArray?
вот текущий пример моей реализации Код: if(fblockSize==0) Название: Re: Чтение с сокета без QDataStream Отправлено: ilyagoo от Май 01, 2011, 19:30 ну да, qint64 QIODevice::read ( char * data, qint64 maxSize )
Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 11:56 Вот что у меня получилось.
Код: void QGenericArmClient::readyRead() Код: int bytesAvail = fsocket->bytesAvailable(); //сколько еще в буфере данных? Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 12:25 интересно, что некоторые пакеты не приходят, по карайней мере я не получаю сигнал readyRead, когда например в другой программе(которая работает по этому же протоколу но написанной под QNX на socket API) все приходит. В чем может быть проблема?
В данном случае, я ожидаю пакет длиной 48 байт. Ощущение ,что пакеты меньше или равные 48 байтам мне не доходят. Название: Re: Чтение с сокета без QDataStream Отправлено: kuzulis от Июнь 29, 2011, 12:38 Цитировать может прийти часть следующего пакета? Да, может.Анализируй заголовок и т.п. через метод peek() к примеру, а потом, если все проверки прошли, то читай через read(). И вообще, неизвестен твой протокол обмена. Что он из себя представляет? т.к. алгоритм чтения/парсинга входящего пакета напрямую зависит от протокола. Раз у тебя в пакете есть заголовок, то ИМХО, разбей архитектуру своего приложения по модели ISO/OSI например на два уровня: 1. Канальный 2. Уровень приложений. Канальный уровень будет парсить то что принялось в буфер сокета: синхронизироваться и проверять заголовки входящих данных и т.п., и при успешной проверке - вырезать из пакета заголовок, а оставшиеся данные передавать уровню приложений для дальнейшей обработки и т.п. Цитировать В данном случае, я ожидаю пакет длиной 48 байт. Ощущение ,что пакеты меньше или равные 48 байтам мне не доходят. Ну и что что 48, может придти в один раз 15 байт, а в другой - 80 байт. Поэтому, нельзя, читая первые байты пакета, думать, что эти данные являются заголовком.. А может заголовок - где-то в середине пакета, а первые байты - это мусор, оставшийся от предыдущего пакета и т.п. Вот тебе, для ознакомления ссылочка на паттерн при разработки сетевых (да и нетолько) приложений (как один из многих вариантов паттернов): http://www.eventhelix.com/realtimemantra/patterncatalog/protocol_layer.htm Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 13:59 Я так и не понял к чему то что по ссылке?
А наш протокол довольно протостой. Есть заголовок в виде структуры, у которой несколько полей. Код: typedef struct На клиенте мне нужно получить даголовок и данные если есть за ним. Название: Re: Чтение с сокета без QDataStream Отправлено: RedDog от Июнь 29, 2011, 14:12 Прям так структурой и передается?
А если разное выравнивание будет на сервер и клиенте? Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 14:13 выравнивание мы привели к одинаковому значению.
например проблем на qnx клиенте не возникает, и все данные приходят как надо. но механизм приема там немного другой в силу специфики ОС. Название: Re: Чтение с сокета без QDataStream Отправлено: kuzulis от Июнь 29, 2011, 14:19 Цитировать Я так и не понял к чему то что по ссылке? Очень плохо. Цитировать Есть заголовок в виде структуры, у которой несколько полей. Опять 25.... Ты сначала должен определить где же всё-таки находится заголовок в массиве тех байт, которые принял сокет. Не факт, что первые sizeof(scb_msg_t) байт в буфере будут заголовком. Иначе можешь оч сильно нарваться на неприятности... Цитировать На клиенте мне нужно получить даголовок и данные если есть за ним. Получай.Цитировать выравнивание мы привели к одинаковому значению. Выравнивание тут ни при чем.Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 14:23 предложите ваш вариант?
сервер уже написан (писал не я) и работает. т.е. в начало и конец заголовка положить сигнатуру? потом в очередном peek её искать? если нашёл, тогда уже читать как выше изложено? Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 14:27 дело в том, что многие данные из p1-p8 используются, поэтому вырезать заголовок не имеет смысла
Название: Re: Чтение с сокета без QDataStream Отправлено: kuzulis от Июнь 29, 2011, 14:27 Цитировать т.е. в начало и конец заголовка положить сигнатуру? аха.потом в очередном peek её искать? если нашёл, тогда уже читать как выше изложено? ищем заголовок, смотрим сколько там указано байт данных после него, прыгаем туда, и ищем после данных конечную сигнатуру. и если всё ок, то пакет вынимаем. если же пакет не полный пришел, то ждем пока он наполнится, а потом уже анализируем Цитировать дело в том, что многие данные из p1-p8 используются, поэтому вырезать заголовок не имеет смысла значит не вырезайВ общем, думай сам. Тебе виднее как у вас там что сделано. Название: Re: Чтение с сокета без QDataStream Отправлено: kuzulis от Июнь 29, 2011, 14:35 Цитировать т.е. в начало и конец заголовка положить сигнатуру? бррр...и в заголовок сигнатуру и в конец пакета. например: <0x68><len><len><0x68><data><0x16> В общем, что-то типа кадров формата FT xxx сделай. ИМХО, так будет надежнее чем то что есть сейчас. Нечего придумывать новое, если все уже придумано за вас. PS: можно еще и CRC впихнуть Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 14:50 но ведь может возникнуть ситуация когда сигнатура начала/конца может оборваться и прийти (или не прийти хотя маловероятно в случае TCP) в другом пакете. как тогда быть?
Название: Re: Чтение с сокета без QDataStream Отправлено: kuzulis от Июнь 29, 2011, 14:58 ждать пока придет
Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 15:20 вот кусок кода чтения клиента под QNX где все работает: (хотя без каких либо проверок пока)
Код: void * thread_func(void * params) Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 16:04 вот как лучше сделать?
я думаю, сначала пакета ставить сигнатуру, например 'PACKBGN',/0, потом uint16_t lenght, потом данные если есть, в конце 'PACKEND',/0. может в будущем и CRC. теперь я так понимаю, сначала делаю peek. далее надо найти в памяти сигнатуру начала. потом получить размер оставшийся, и копировать в буфер данные с сокета пока не получу сигнатуру конца или размер принятых данных не будет равен размеру, который шел после сигнатуры начала. так делать? а если сигнатура обрывается где то по середине? тогда какого размера брать буфер чтения? Название: Re: Чтение с сокета без QDataStream Отправлено: Fregloin от Июнь 29, 2011, 16:30 QAbstractSocket::LowDelayOption - частично решил проблему, теперь все приходит нормально (хотя конечно проверку я введу, но когда приедет разработчик сервера).
теперь непонятная проблема - когда я шлю на сервер запрос, открыть файл, то в ответ должен прийти пакет данных (структура scb_msg_t без данных за ней). И вот клиент QNX ее получает, а в Qt сигнал readyRead() не получаю. В чем может быть загвостка? |