crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> QTcpSocket. write., ошибка параллельной записи данных.
leonneon_89
  опции профиля:
сообщение 5.4.2013, 11:29
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 5.4.2013
Пользователь №: 3779

Спасибо сказали: 0 раз(а)




Репутация:   0  


В общем немного о программе.
Есть клиент, который выполняет функции:
1. Отправлять запрос серверу.
2. Отправлять сообщения серверу.
3. Получать сообщения от сервера.
Есть сервер, выполняющий функции:
1. Он получает сообщения от клиента производит действия на сервере, отсылает ответ.
2. Сам посылает сообщения клиенту.

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

Сервер состоит из clientsocket.h - наследуется от QTcpSocket в котором производятся вычисления, server.h - наследуется от QTcpServer переопределяет incomingConnection и главной функции.

На сервере clientsocket.cpp используем QTimer для посылки самостоятельных сообщений клиенту.

slot для отправки сообщений.
void ClientSocket::sendSignalLevel()
{  
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_7);

    out << quint16(0);//размер сообщения
    out << signalLevel_d2;//команда клиенту
    out << signalLevel_;//уровень сигнала int

    out.device()->seek(0);
    out << quint16(block.size() - sizeof(quint16));
    write(block);
}


Так же, там есть функция отправки ответа на сообщения клиента.
void ClientSocket::readClient()
{
    QDataStream in(this);
    in.setVersion(QDataStream::Qt_4_7);
    if (nextBlockSize == 0)
    {
        if (bytesAvailable() < (int)sizeof(quint16))
            return;
        in >> nextBlockSize;
    }
    if (bytesAvailable() < nextBlockSize)
        return;
    else
        nextBlockSize = 0;
    //3 байт - команда серверу
    quint8 commandClient;
    in >> commandClient;
    qDebug() << "Received command " << commandClient;
  
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_7);

    //команды от клиента
    switch(commandClient)
    {
        case powerOn_d1 :
        {
            d1.powerState = true;
            //size of data
            out << quint16(0);
            //command to client
            out << powerOn_d1_Good;
            out << d1.powerState << d1.attenuatorValue << d1.amperage_voltage_conformity
                << d1.amperage << d1.voltage;
            break;
        }
        ....
    }
    out.device()->seek(0);
    out << quint16(block.size() - sizeof(quint16));
    qDebug() << "transmitted size of block: " << quint16(block.size() - sizeof(quint16));

    write(block);
}


Вообщем у меня возник вопрос.
Когда клиент посылает много сообщений серверу. Мне кажется сервер иногда не успевает обрабатывать, все полученные сообщения от клиента и отсылает только некоторые из них, из за этого клиент работает не корректно. Есть предположение что сервер не успевает записывать данные в сокет, так как он в то же время посылает уровень сигнала клиенту. Я на сервере используются две функции write(). Как мне избавится от такой проблемы, чтобы сервер принимал все сообщения от клиента и записывал все ответы, и в то же время посылал уровень сигнала в виде сообщения?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 5.4.2013, 12:16
Сообщение #2


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Цитата
Мне кажется сервер иногда не успевает обрабатывать, все полученные сообщения от клиента и отсылает только некоторые из них, из за этого клиент работает не корректно.


А что qDebug, подтверждает факт потери сообщений?

Цитата
Есть предположение что сервер не успевает записывать данные в сокет, так как он в то же время посылает уровень сигнала клиенту.

В то же время он не может ничего делать, если у него не несколько тредов/процессов.
Сигналы/слоты НЕ обрабатываются, пока управление не вернется к event loop.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
leonneon_89
  опции профиля:
сообщение 5.4.2013, 12:54
Сообщение #3


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 5.4.2013
Пользователь №: 3779

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата
А что qDebug, подтверждает факт потери сообщений?


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

Цитата
В то же время он не может ничего делать, если у него не несколько тредов/процессов.
Сигналы/слоты НЕ обрабатываются, пока управление не вернется к event loop.


Получается QTimer блокирует вызов Сигналов/слотов? И мне надо использовать треды для решения этой проблемы?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 8.4.2013, 8:40
Сообщение #4


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Цитата
Получается QTimer блокирует вызов Сигналов/слотов? И мне надо использовать треды для решения этой проблемы?


Ни в коем случае не надо использовать треды для решения проблемы! Это только добавит проблем.
write не блокирующая функция.

Приложите мимнимальный проект, который иллюстрирует проблему.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
leonneon_89
  опции профиля:
сообщение 8.4.2013, 12:58
Сообщение #5


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 5.4.2013
Пользователь №: 3779

Спасибо сказали: 0 раз(а)




Репутация:   0  


В общем, вот проект. SupplyUnitMMA - клиент, tripserver - сервер.
сначала запускаем сервер, а потом клиент. Ошибка появляется, когда мы включаем клиент, запускаем автоматический режим, потом переходим в ручной и начинаем быстро изменять положение аттенюатора блока управления, после этого аттенюатор начинает работать не корректно.
Будут вопросы по проекту пишите, постараюсь пояснить детали.

Прикрепленные файлы
Прикрепленный файл  Project.zip ( 18.3 килобайт ) Кол-во скачиваний: 121
 
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 8.4.2013, 16:49
Сообщение #6


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


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

Итак после поворота ручки клиент посылает серверу сообщение об изменении, в ответ тот посылает одобрение:
 case ClientSocket::attenuatorChange_d2_Good :

Клиент, будучи доволен одобрением выставляет ручку аттеньюатора в одобренное значение: 8)
ui_.attenuatorValue_d2->setValue(attenuatorValue);

Однако коварный Qt подготовил ловушку в виде отслеживания изменения ручки! :blink:
connect(ui_.attenuatorValue_d2, SIGNAL(valueChanged(int)), this, SLOT(setAttenuatorValue_D2(int)));

Не успело новое значение примениться, как слот спешит доложить новое значение серверу: :o:
    commandClient_ = ClientSocket::attenuatorChange_d2;
    emit requestSent();

Который успешно его получает: :huh:
case attenuatorChange_d2 :

и отправляет свое одобрение: ;)
//command to client
out << attenuatorChange_d2_Good;

Что возвращает нас к началу нашей истории :lol: .
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
leonneon_89
  опции профиля:
сообщение 9.4.2013, 10:28
Сообщение #7


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 5.4.2013
Пользователь №: 3779

Спасибо сказали: 0 раз(а)




Репутация:   0  


Спасибо за подробный ответ, у меня возник еще небольшой вопрос, если мы посылаем серверу первоначальный запрос всех состояний, и он нам возвращает сообщение в котором находятся состояния всех аттенюаторов, аттенюаторов у нас несколько штук, мы сохраняем их состояния, в это время все они испускают сигнал об изменении, которые в свою очередь соединяются со своими сигналами и посылают одновременно сообщения серверу о своих изменившихся состояниях. Как это можно избежать? Или можно поставить connection в очередь, чтобы они посылались поочередно? Если у нас два соединения, то можно у одного поставить атрибут Qt::QueuedConnection, который встанет в очередь после connection без атрибута, а если у нас три или более connection, то как тогда быть?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 9.4.2013, 13:27
Сообщение #8


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Я заводил флаг.
Когда сервер присылает команду на изменение - выставляем флаг, после применения всех изменений - сбрасываем.
В обработчике события изменения значения оповещаем сервер только если флаг не установлен (изменение происходит от пользователя).
Единственная тонкость - нельзя использовать QueuedConnection, поскольку оно вызовется уже после сброса флага.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
leonneon_89
  опции профиля:
сообщение 9.4.2013, 22:44
Сообщение #9


Студент
*

Группа: Участник
Сообщений: 20
Регистрация: 5.4.2013
Пользователь №: 3779

Спасибо сказали: 0 раз(а)




Репутация:   0  


Спасибо, теперь стало более понятней. :D
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 17.2.2025, 11:12