Russian Qt Forum
Июнь 15, 2024, 16:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: "Левые" пакеты с непонятно чем при передаче через QTCPSocket  (Прочитано 10698 раз)
vulko
Гость
« : Март 03, 2014, 08:17 »

Всем привет.

Сделал tcp сервер и клиент для непрерывного обмена данными.

Сервер - слегка переделанный fortune server, клиент писался с нуля, т.к. работает в отдельном потоке.

Суть работы такая - клиент делает запрос серверу, тот отвечает записывая в сокет 128 байт данных. Клиент получает, десериализует данные и дисконнектится. По сигналу дисконнекта, небольшой delay и снова запрос данных с сервера.
И так до бесконечности.

В принципе все прекрасно работает, но иногда приходит сокет размера 4224 байт.
Откуда берется такой сокет не понимаю...
Пока что просто игнорирую все сокеты размером не 128 байт, но все таки хотелось бы понять что это за пакет такой...

Заранее спасибо за ответы.
« Последнее редактирование: Март 03, 2014, 09:23 от vulko » Записан
OKTA
Гость
« Ответ #1 : Март 03, 2014, 09:26 »

Для начала прочитайте, что такой "сокет" и что такое "пакет tcp", чтобы не путаться в определениях. И да, как уже писал в другом треде, посмотрите, что в этих данных лежит + следите за тем, что и сколько байт отправляет сервер.
Записан
vulko
Гость
« Ответ #2 : Март 03, 2014, 10:17 »

Для начала прочитайте, что такой "сокет" и что такое "пакет tcp", чтобы не путаться в определениях. И да, как уже писал в другом треде, посмотрите, что в этих данных лежит + следите за тем, что и сколько байт отправляет сервер.

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

Добавил небольшой кусок кода для логирования необычного пакета:
Код:
    if (pTcpSocket->size() != 128) {
        qDebug() << in;
        qDebug() << "______________________________________";
        in.device()->dumpObjectInfo();
        qDebug() << "______________________________________";
        in.device()->dumpObjectTree();
        pTcpSocket->disconnect();

        return;
    }

Судя по логам, в буфере сокета лежит фигпойми что...
Цитировать
QVariant(bool, true)
______________________________________
______________________________________

Если я правильно понимаю, QVariant это в принципе что угодно...


Возможно неверная логика сервера?
Не хватает чего-то после write()?
Кстати сервер рапортует всегда о том что отправил 128 байт, огромные сокеты только у клиента...

Код:
    QTcpSocket tcpSocket;
    if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
        qDebug() << "TCPSocketError" << tcpSocket.error();
        emit error(tcpSocket.error());
        return;
    }

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_8);
    out.setByteOrder(QDataStream::BigEndian);
    out.setFloatingPointPrecision(QDataStream::SinglePrecision);
    DataServer *srv = (DataServer*) parent();

    for(int i = 0; i < num_data; i++) {
// сериализуем...
    }

    qDebug() << "sending: " << out.device()->size() << " bytes...";
    tcpSocket.write(block);

    tcpSocket.disconnectFromHost();
    if (tcpSocket.state() == QAbstractSocket::UnconnectedState ||
        tcpSocket.waitForDisconnected(1000))
        qDebug() << "sent!" << "socket state: " << tcpSocket.state();

п.с. вышеприведенный код сервера выполняется в отдельном потоке (как в fortune server).
« Последнее редактирование: Март 03, 2014, 10:24 от vulko » Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #3 : Март 03, 2014, 10:39 »

очевидно что данные пакетов буферизируются, и не вычитываются полностью клиентом.
если есть уверенность что пакеты всегда длиной 128 байт, можно задать размер буфера чтения сокета этому объему (это большой костыль, но сможет помочь поидее).
приведите код чтения сокета, что бы было понятней как вы читаете данные.
Записан
OKTA
Гость
« Ответ #4 : Март 03, 2014, 10:44 »

Тавтология не имеет здесь места вообще) Сокет и пакет абсолютно разные вещи и лучше использовать понятия в нужном месте и в нужное время, а то может встать боком в будущем - на каком-нибудь собеседовании ляпнете и будет ахтунг  Обеспокоенный
А еще лучше для теста увеличьте размер пакета и посмотрите, увеличивается ли размер "залипшего" пакета. Слипание пакетов в один - частая проблема с сокетами по началу.
Записан
vulko
Гость
« Ответ #5 : Март 03, 2014, 11:05 »

очевидно что данные пакетов буферизируются, и не вычитываются полностью клиентом.
если есть уверенность что пакеты всегда длиной 128 байт, можно задать размер буфера чтения сокета этому объему (это большой костыль, но сможет помочь поидее).
приведите код чтения сокета, что бы было понятней как вы читаете данные.

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

запись:

Код:
void ServerThread::run()
{
    QTcpSocket tcpSocket;
    if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
        qDebug() << "TCPSocketError" << tcpSocket.error();
        emit error(tcpSocket.error());
        return;
    }

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_8);
    out.setByteOrder(QDataStream::BigEndian);
    out.setFloatingPointPrecision(QDataStream::SinglePrecision);
    DataServer *srv = (DataServer*) parent();

    for(int i = 0; i < num_data; i++) {
        out << srv->struct[i].int;
        out << srv->struct[i].float;
        out << srv->struct[i].float;
        out << srv->struct[i].float;
    }

    qDebug() << "sending: " << out.device()->size() << " bytes...";
    tcpSocket.write(block);

    tcpSocket.disconnectFromHost();
    if (tcpSocket.state() == QAbstractSocket::UnconnectedState ||
        tcpSocket.waitForDisconnected(1000))
        qDebug() << "sent!" << "socket state: " << tcpSocket.state();
}


чтение

Код:
void IncomingDataHandler::readData()
{
    qDebug() << "socket data recieved: " << pTcpSocket->size() << " bytes";
    QDataStream in(pTcpSocket);
    in.setVersion(QDataStream::Qt_4_8);
    in.setByteOrder(QDataStream::BigEndian);
    in.setFloatingPointPrecision(QDataStream::SinglePrecision);

    if (pTcpSocket->size() != 128) {
        pTcpSocket->disconnect();

        return;
    }

    for(int i = 0; i < 8; i++) {
        in >> struct[i].int
        in >> struct[i].float
        in >> struct[i].float
        in >> struct[i].float
    }

    if(in.atEnd()) {
        qDebug() << "end of data...";
        emit newData(struct*);
    }
}
Записан
OKTA
Гость
« Ответ #6 : Март 03, 2014, 11:14 »

Фишка в том, что когда используется tcpSocket.write(block);, данные пишутся не прямо в сеть грубо говоря, а в буффер. И дальнейшее  - уже дело протокола - или он сразу отправит данные или потом. Можно после write поставить flush попробовать.
Записан
vulko
Гость
« Ответ #7 : Март 03, 2014, 11:42 »

Фишка в том, что когда используется tcpSocket.write(block);, данные пишутся не прямо в сеть грубо говоря, а в буффер. И дальнейшее  - уже дело протокола - или он сразу отправит данные или потом. Можно после write поставить flush попробовать.

flush не помогает, пробовал. поскольку 128 байт отправляю, решил его вообще убрать...

это понятно что сетевые пакеты это не тоже самое что буфер сокета... и я бы мог понять откуда вдруг берется такой пакет, если бы например я бы записывал туда непрерывно... но я пишу порцию 128 байт, дисконекчу сокет на сервере, на клиенте буфер приходит, читается, уходит в другой поток на обработку и приходит сигнал disconnected(), после которого уже идет новый запрос на сервер, и тот снова отправляет 128 байт...
как может придти буфер в 4224 байта непонятно... то ли это кривость сокетов в qt, то ли виртуалка виновата... хз даже...

на винде что ли попробовать это безобразие протестить...
Записан
OKTA
Гость
« Ответ #8 : Март 03, 2014, 11:47 »

Попробуй ради интереса прочитать первые 128 байт пакета этого кривого, словно там нормальный твой пакет лежит)
Записан
Bepec
Гость
« Ответ #9 : Март 03, 2014, 12:01 »

А по хорошему надо бы снифером полирнуть пакеты и выложить парочку нормальных и свой ненормальный Веселый
Записан
vulko
Гость
« Ответ #10 : Март 03, 2014, 12:29 »

Попробуй ради интереса прочитать первые 128 байт пакета этого кривого, словно там нормальный твой пакет лежит)

sigsegv. собсно с этого и началось, только потом выяснилось что пакет приходит не 128 байт...

А по хорошему надо бы снифером полирнуть пакеты и выложить парочку нормальных и свой ненормальный Веселый

с удовольствием. я тока wireshark'ом пользовался. что под линух посоветуешь? чтобы не через package manager тока, а с инсталятором был... а то у меня линух супер кастомный какой-то... :/


п.с. попробовал под виндой (qt 5.2.0 + mingw 4.Крутой, так тут вообще вылетает при иногда при десериализации последнего поля структуры. попробовал добавить перед for'ом waitforreadyread (хотя судя по описанию это надо не в хэндлере сигнала readyread вызывать...Улыбающийся ), теперь на нём sigsegv... причем это тока на дебаге происходит, в релизе все чудесно...))
я конечно и раньше догадывался, что лучше жабы ничего кроссплатформеного нет... теперь точно уверен)))
« Последнее редактирование: Март 03, 2014, 12:32 от vulko » Записан
OKTA
Гость
« Ответ #11 : Март 03, 2014, 12:39 »

http://www.ethereal.com
Записан
vulko
Гость
« Ответ #12 : Март 03, 2014, 13:02 »


там какой-то cloud service... сайт не валидный уже
Записан
OKTA
Гость
« Ответ #13 : Март 03, 2014, 13:12 »

Тогда http://www.wireshark.org/  Смеющийся ибо это одно и тоже  Смеющийся
Записан
vulko
Гость
« Ответ #14 : Март 03, 2014, 13:49 »

Тогда http://www.wireshark.org/  Смеющийся ибо это одно и тоже  Смеющийся

попробовал под виндой wireshark'ом посмотреть, но ничего толкового из этого не вышло...
порт для сокета выставляю 777, по факту пакеты идут левыми портами... в общем ничего толкового из этих пакетов я не понял... все таки это не какой-нибудь sip, где все предельно четко и понятно...

если вы понимаете в этом что-то, могу закинуть сюда pcap.


однако логирование под виндой и дебаг кое-что помогли выявить... (под виртуалкой линуха в qt creator'е не вижу почти никакие локальные переменные и не могу оценивать выражения и т.п... не отображаются тупо...).

в общем модифицировал немного код:

Код:
    int size = pTcpSocket->size();
    qDebug() << "socket data recieved: " << size << " bytes";

...

    if (size != 128) {
        qDebug() << "wrong socket " << size << " : " << pTcpSocket->size();
        qDebug() << in.device()->size();
        qDebug() << "________________________________________________________";
        QByteArray arr = in.device()->readAll();
        qDebug() << arr.size();
        qDebug() << "________________________________________________________";
        pTcpSocket->disconnect();

        return;
    }
...

и что же я увидел...
Цитировать
socket data recieved:  4224  bytes
wrong socket  4224  :  128
128
________________________________________________________
128
________________________________________________________


то есть на момент попадания в if (size != 128), размер буфера сокета из 4224 вновь превратился в 128, и в QDataStream (in) лежит массив из 128 байт... чудесно...


возникла идея, возможно виновата QEventLoop?
Т.к. сокет обрабатывается в отдельно потоке и после tcpSocket->connectToHost() делается loop.exec, которая закончится только когда придет сигнал disconnected() от сокета...

Может в этом дело?

Код:
void IncomingDataHandler::run()
{
    qDebug() << "IncomingDataHandler thread started!";
    QEventLoop evLoop;

    pTcpSocket = new QTcpSocket;
    pTcpSocket->moveToThread(this);
    //pTcpSocket->setSocketDescriptor(socketDescriptor);
    //socketDescriptor = pTcpSocket->socketDescriptor();
    connect(pTcpSocket, SIGNAL(readyRead()), this, SLOT(readData()));
    connect(pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(connectionError(QAbstractSocket::SocketError)));
    connect(pTcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
    connect(this, SIGNAL(dataProcessed()), &evLoop, SLOT(quit()));
    //connect(pTcpSocket, SIGNAL(disconnected()), &evLoop, SLOT(quit()));

    while (running) {
        requestData();
        evLoop.exec();
        //qDebug() << "socket disconnected... requesting new data";
    }
}

void IncomingDataHandler::requestData()
{
    // TODO: remove sleep. temporary solution.
    QThread::msleep(500);

    qDebug() << "requesting data from server...";

    // connect to server
    pTcpSocket->connectToHost(ipAddress, 777);
}
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.047 секунд. Запросов: 19.