Название: Проблема с TCP Отправлено: Shaman13 от Июль 31, 2006, 13:48 Добрый день,
имеется такая задача: на машине-сервер запущен gui, который по нажатию кнопки должен отображать живое видео, которое посылается машиной-клиентом. По нажатию другой кнопки передача видео должна прекратиться. Для передачи видеокартинок от клиента к серверу я использую функцию connectToHost, которая вызывает сигнал newConnection на сервере, где и происходит прием данных и отсылка их в gui. Для передачи команд от сервера клиенту (начать/прекратить отсылку картинок) я отсылаю соответствующие коды с помощью QDataStream (картинки пересылаются аналогично). Команды ловятся сигналом клиента readyRead. Теперь проблема - когда идет передача видео, и я отсылаю команду, что пора прекращать, сигнал readyRead возникает на клиенте примерно в 30% случаев. Единственное объяснение, которое я могу придумать - клиент непрерывно отсылает картинки и поэтому пропускает посланные ему команды. Пробовал всякие waitForReadyRead, waitForBytesWritten, ничего не помогает. В чем тут может быть проблема? Заранее спасибо. Название: Проблема с TCP Отправлено: C.H. от Июль 31, 2006, 14:13 поидее все должно быть наоборот, клиент это там где смотришь, а тот который посылает - это сервер.
Что будешь делать когда захочешь с двух или более машин смотреть картинку??? А по делу - исходники в студию! Какой Ку? Потоки еще какие-то крутятся??? Название: Проблема с TCP Отправлено: Shaman13 от Июль 31, 2006, 15:33 Вообще-то такая задача и стоит, машин будет несколько. Я так понял, одна - сервер, а остальные - клиенты, которые будут коннектиться к серверу и выполнять то, что он им скажет (в частности, передавать видео). Подразумеваетя, что инициировать передачу данных может как сервер, так и клиент.
Qt 4.0 Кода слишком много, но упрощенно примерно так: На сервере: Код:
На клиенте: Код:
Проблема в том, что OnReadyRead на клиенте срабатывает через раз при нажатии на BtnStopLiveVideo на сервере... Название: Проблема с TCP Отправлено: C.H. от Июль 31, 2006, 15:40 пример с threadedfortuneserver и клинетом пробовал?
Без таймера, с потоком? Почитай Книгу "C++ GUI Programming with Qt 4 By Jasmin Blanchette, Mark Summerfield" Там есть пример аля threadedfortuneserver. Глава 14. Writing TCP ClientServer Applications Название: Проблема с TCP Отправлено: Alqualos от Август 01, 2006, 22:56 Так, во-первых: поставить последний Qt 4.1.4. С 4.0 столько багов пофиксено, что не перечесть.
Во-вторых, есть всякая разная буферизация. Хорошо бы проверить каким-нибудь tcpdump'ом (или какой-нибудь аналогичной виндовой дрянью), есть ли реальная передача данных в сети по указанному порту вроде: tcpdump -i eth0 tcp port 9999 Если нет передачи, то может дело в буферизации и имеет смысл использовать какой-нибудь flush(). Были у меня подобные проблемы, так я их и решал, вполне успешно. Правда, то было с QTextStream и там была буферизация в самом классе, а не в QTcpSocket (в QDataStream вроде ничего похожего нет). Остаётся, правда, вопрос, не может ли этот flush внезапно вызвать блокировку (например, если сетевой буфер переполнен), но я его не разбирал, просто забив ^_^ Ах да, ещё, опять же из-за буферизации, данные могут приходить одной порцией. То есть на сервер может прийти сразу несколько сообщений пачкой. Согласно документации, readyRead() будет вызван один раз в таком случае. Так что там чтение надо бы в цикле сделать и bytesAvailable() проверять. Пачки опять же можно посмотреть tcpdump'ом. Название: Проблема с TCP Отправлено: Shaman13 от Август 08, 2006, 19:16 Сделал через среды, поменял сервер и клиент местами - вроде все работает пока что...
Название: Проблема с TCP Отправлено: Joe от Август 10, 2006, 02:13 В продолжение темы. Я почти в отпаде, говоря честно :(
Есть не-шибко простая система - клиент один, рассылает серверам пакеты, сервера - простые guiless, в одном потоке просто ждут, пока придёт чего, хавают данные - и возвращают всё назад и ждут дальше. Идиллия. Так вот в чём засада. Когда я проектировал и собирал первую версию, была qt4.1.1 - и хорошо было. Начиная с 4.1.3 - не работет как надо (не проверял 412, может там тоже всё плохо). Засада в том, что или не передаётся от клиента весь запрос в какой-то момент - или не приходит к "серверу" всё. Блин, ну на одной машине когда сидят, как это может не дойти? всякие wautForBytesWritten и flush на клиенте не приводят ни к какому ощутимому результату. код "сервера" - #include <iostream> using namespace std; #include <QCoreApplication> #include <QDataStream> #include<QTcpSocket> #include <QColor> #define clamp(x,min,max) (x <= min ? min : (x >= max ? max : x)) typedef float float3[3]; struct bucketDim { int w, h; float dx0, dx1, dy0, dy1; }; struct geobucket : bucketDim { float3* P; float3* V; geobucket() {}; geobucket(const bucketDim *src) { *(bucketDim*)this = *src; P = NULL; V = NULL; }; ~geobucket() {}; }; struct imgbucket : bucketDim { float3* C; float* a; imgbucket(const bucketDim *src) { *(bucketDim*)this = *src; C = NULL; a = NULL; }; ~imgbucket() { if(C != NULL) delete [] C; if(a != NULL) delete [] a; }; }; enum packetType { unknownPacket = 0, imagePacket, shaderParameter, shutdownRenderNode, packetTypeForce = 0xffffffff }; geobucket* readGeo(quint32 blockSize, QDataStream&in); bool flushUnknown(quint32 blockSize, QDataStream&in); imgbucket* render(geobucket*); int main(int argc, char *argv[]) { //QCoreApplication a(argc, argv); QTcpSocket socket; socket.connectToHost("localhost", 5005); if(!socket.waitForConnected()) { cout << "FAILED CONNECTION" << endl; }; // HANDSHAKING { QDataStream in(&socket); in.setVersion(QDataStream::Qt_4_0); quint16 blockSize; while(socket.bytesAvailable() < (int)sizeof(quint16)) { if (!socket.waitForReadyRead(5000)) { cout << "WAIT TIMEOUT" << endl; return -1; } } in >> blockSize; while(socket.bytesAvailable() < blockSize) { if (!socket.waitForReadyRead(5000)) { cout << "WAIT TIMEOUT" << endl; return -1; } } QString info; in >> info; QByteArray ba = info.toAscii(); cout << "HANDSHAKE: " << ba.constData() << endl; // SEND HANDSHAKE QByteArray block; QDataStream buff(&block, QIODevice::WriteOnly); buff.setVersion(QDataStream::Qt_4_0); buff << (quint16)0; buff << QString("Bla-Bla"); buff.device()->seek(0); buff << (quint16)(block.size() - sizeof(quint16)); socket.write(block); socket.waitForBytesWritten(-1); cout << "HANDSHAKING SUCCESSFULL" << endl; } ------- тут всё отлично проходит // MAIN LOOP int bc = 0; QDataStream in(&socket); in.setVersion(QDataStream::Qt_4_0); while(true) { // READ quint64 baa; // Bytes Available while((baa = socket.bytesAvailable()) < 2*sizeof(quint32)) { if (!socket.waitForReadyRead(-1)) // WAIT AND ALL { cout << "WAIT TIMEOUT" << endl; break; } } quint32 blockSize; in >> blockSize; quint32 packet; in >> packet; ---------------- а вот здесь приключения ----------------один/два раза весь цикл выполняется полностью и хорошо, всё чо надо приходит, но в какой-то момент здесь bytesAvaialble возвращает недостаточное число байт, и в socket перестают поступать данные если включить не вечное ожидание, а определить интервал - это не помогает, всё равно bytesAvailable показывает недостаток данных. while((baa = socket.bytesAvailable()) < blockSize) { if(!socket.waitForReadyRead(-1)) { //cout << "WAIT TIMEOUT" << endl; //break; } } --------самая чушь в том, что если из клиента в socket плюнуть ещё хоть 1 байт, пока "сервер" в таком клинче, то всё сдвинется с мёртвой точки. Но это палиатив, проблема-то появилась в поздних версиях. И в 4.2.tp2 она тоже есть, весьма прискорбно. geobucket* bucket = NULL; switch(packet) { case imagePacket: bucket = readGeo(blockSize,in); break; case shutdownRenderNode: { cout << "TERMINATING EVENT OCCURED!" << endl; exit(0); return 0; } default: if(!flushUnknown(blockSize,in)) return NULL; break; }; cout << "RECEIVED BUCKET: [" << bucket->dx0 << "," << bucket->dx1 << "]:[" << bucket->dy0 << "," << bucket->dy1 << "] (" << bucket->w << "x" << bucket->h << ")" << endl; cout << "BLOCKZISE: " << blockSize << endl; imgbucket* img = render(bucket); // WRITE QByteArray block; QDataStream buff(&block, QIODevice::WriteOnly); buff.setVersion(QDataStream::Qt_4_0); // PACKETSIZE buff << (quint32)0; // PACKET TYPE buff << (quint32)imagePacket; // BUCKET { buff << img->dx0 << img->dx1 << img->dy0 << img->dy1 << img->w << img->h; } int cnt = img->w*img->h; // C { for(int i=0;i<cnt;i++) { buff << img->C
buff << img->C[2]; } } // a { for(int i=0;i<cnt;i++) buff << img->a; } // SETUP PACKET buff.device()->seek(0); blockSize = block.size() - 2*sizeof(quint32); buff << blockSize; // SEND socket.write(block); socket.flush(); socket.waitForBytesWritten(-1); cout << "SENT BUCKET: [" << img->dx0 << "," << img->dx1 << "]:[" << img->dy0 << "," << img->dy1 << "] (" << img->w << "x" << img->h << ")" << endl; cout << "BLOCKZISE: " << blockSize << endl; } socket.disconnectFromHost(); socket.waitForDisconnected(3000); return 0; } geobucket* readGeo(quint32 blockSize, QDataStream&in) { bucketDim dim; in >> dim.dx0 >> dim.dx1 >> dim.dy0 >> dim.dy1 >> dim.w >> dim.h; geobucket* bucket = new geobucket(&dim); int cnt = bucket->w*bucket->h; bucket->P = new float3[cnt]; for(int i=0;i<cnt;i++) { in >> bucket->P
in >> bucket->P[2]; }; bucket->V = new float3[cnt]; for(int i=0;i<cnt;i++) { in >> bucket->V
in >> bucket->V[2]; }; return bucket; }; bool flushUnknown(quint32 blockSize, QDataStream&in) { unsigned char b; for(int i=0;i<blockSize;i++) in >> b; return true; }; Что посоветуете? Может я где лох картонный? Название: Проблема с TCP Отправлено: Alqualos от Август 10, 2006, 08:33 Так, а можно это в более приличном виде на laerel at yandex dot ru вместе с файлами, необходимыми для запуска этой штуковины, буде таковые найдутся? А то копипастить кучу текста из форума, комментируя в ней "комментарии", как-то не хочется, а проблема заинтересовала.
Система какая? Винда? Я смогу это проверить только в FreeBSD. Если тут баг не проявится, значит баг в винде, если винда. Что-то такое было в какой-то версии Qt, потом они его обошли, может в 4 это опять всплыло. Если так, надо будет писать им багрепорт. Название: Проблема с TCP Отправлено: Joe от Август 10, 2006, 11:34 Спасибо, но у меня система - винда, xpsp2.eng, мне затеваться с другими конфессиями боюсь что недосуг, под *nix/*nux это тоже портирую, но пока мне нужен макет, который будет чо-то делать и который я могу везде предьявить. Кроме того, чтобы это всё в целости попробовать - нужно ещё кучу софта доставлять - Maya, renderman, сомневаюсь, что оне для bsd существуют. Хотя - ыtandalone вариант клиента для bug-show я могу сделать, не большая проблема, даж сорцы дать, пректом для "сервера" тоже могу поделиться, там ничего военного тоже. Но если не будет ошибки в bsd - не факт, что её нет в depended части qt.
Кстати, компиляется разными компилятрами - пофиг мороз, всё тожсамое. Название: Проблема с TCP Отправлено: Alqualos от Август 10, 2006, 13:06 Лучше всего бы сделать две маленькие программки, только демонстрирующие этот баг. Ага, bug-show.
Кстати, если баг в Qt, есть шанс, что он пропадёт, если выключить буферизацию сокета. После чего ошибку можно будет обойти, сделав собственную буферизацию (если она вообще нужна). Название: Проблема с TCP Отправлено: Joe от Август 10, 2006, 20:05 да, наверное я, при оказии, такой фич сделаю, т.к. это критичная ерунда. Неуверен, что прям щас - я решил проблему, не оч. элегантно, но охота другим заниматься.
Буферизация мне нужна, как мне кажется, и я не очень понял, что мне делать в таком случае - это будет похоже на работу с UDP что-ли? мне это нафиг не надо в таком виде Название: Проблема с TCP Отправлено: C.H. от Август 11, 2006, 06:47 Цитата: "Alqualos" Кстати, если баг в Qt, есть шанс, что он пропадёт, если выключить буферизацию сокета. Как буферезицию в соерте выключить??? Название: Проблема с TCP Отправлено: Alqualos от Август 11, 2006, 08:33 connectToHost(host, port, QIODevice::ReadWrite | QIODevice::Unbuffered)
Сетевой буфер ОС при этом никуда не пропадёт, исчезнет только внутренняя буферизация Qt, а значит и её баги, если таковые имеются. То есть bytesAvailable(), например, будет возвращать количество байт, доступных в дескрипторе сокета напрямую, а не размер своего буфера. Кстати, я вспомнил, где там был баг в винде, вот: http://doc.trolltech.com/3.3/qsocketdevice.html#bytesAvailable Не знаю, может это та же самая проблема в новом воплощении, а может совсем другая. Название: Проблема с TCP Отправлено: Joe от Август 11, 2006, 12:13 ...да, проблема похожа. Но почему она вновь тогда появилась, ведь версия 4.1.1 однозначно хорошо себя ведет, 4.1.3 - уже плохо. Значит, обойти это всё же можно, но trolltech похоже наняли нового программера, и он им всё улучшил назад :) выглядит именно так :)
Название: Проблема с TCP Отправлено: Alqualos от Август 11, 2006, 12:17 Я сравнивал код в 4.1.1 и 4.1.4 - они там, похоже, доделали какие-то фичи в сетевом модуле, которые были не до конца реализованы. Может, попутно напортачили. Правда, я смотрел редакцию X11, может в виндовой версии больше изменений. В любом случае, неплохо было бы, чтобы кто-нибудь написал им багрепорт с прилагающимся примером, демонстрирующим оный баг.
|