crossplatform.ru

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

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> Пропадание сетевого обмена
KuvshinoF
  опции профиля:
сообщение 15.4.2020, 18:14
Сообщение #1


Студент
*

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

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




Репутация:   0  


Программа_1 бесконечно посылает 1 раз в секунду определенный набор байтов, а программа_2 его читает, обрабатывает и визуализирует.
Чтение по udp сетевых данных в программе_2:
  QUdpSocket oUDPSocket;
  QByteArray baoBufRecv;
  unsigned short  usSendPort;
  QHostAddress haoLocalAddr, haoSenderAddr;

  baoBufRecv.resize(65535);
  haoLocalAddr.setAddress("127.0.0.1");
  oUDPSocket.bind(haoLocalAddr, 5000);
  connect(&oUDPSocket, SIGNAL(readyRead()), this, SLOT(sltReadDatagram()));
//-----------------------------------------------------------------------------

void Interaction::sltReadDatagram()
{
  vReadDatagram();
}
//-----------------------------------------------------------------------------

void Interaction::vReadDatagram()
{
  while (_oUDPSocket.hasPendingDatagrams())
  {
     long lSize = oUDPSocket.pendingDatagramSize();
     oUDPSocket.readDatagram(baoBufRecv.data(), lSize, &haoSenderAddr, &usSendPort);
    ...
  }
}

class Interaction: public QThread
{
}


Проблема в том, что программа_2 принимает всего около 10 сетевых посылок, а потом vReadDatagram перестает вызываться, как будто перестают идти данные от программы_1, но это не так (проверено индикацией данных от программы_1 в простейшей программе_3 и tcpdump-ом). Программа_2 достаточно сложна (многопоточна, gui c opengl) и что может приводить к такому "сетевому обрыву" - непонятно.

Сообщение отредактировал KuvshinoF - 20.4.2020, 11:35
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 16.4.2020, 8:51
Сообщение #2


фрилансер
******

Группа: Участник
Сообщений: 2941
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


попробуй вот так
    auto size=oUDPSocket->bytesAvailable();
    if(size>0 && oUDPSocket->hasPendingDatagrams())
    {

    }


+самостоятельно периодически подпинывай вызов слота vReadDatagram


(у меня вычитывание делается в отдельном потоке, сигналы не ловлю, просто вычитываю постоянно, поэтому такое не замечаю)


Цитата(KuvshinoF @ 15.4.2020, 20:14) *
как будто перестают идти данные от программы_1


это проверяется при помощи акулы (WireShark)
Если отсылка с локалхоста на локалхост, то нужно включить loopback либо кидать с виртуалки на хост

Сообщение отредактировал Алексей1153 - 16.4.2020, 8:52
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
KuvshinoF
  опции профиля:
сообщение 16.4.2020, 14:11
Сообщение #3


Студент
*

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

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




Репутация:   0  


А внутри указанного Вами выше кода (проверка bytesAvailable()) вызов vReadDatagram(), то есть этот код надо добавить в sltReadDatagram? Какой тогда в этом смысл, если я ставил принт в vReadDatagram и он переставал идти, значит переставала вызываться vReadDatagram, а следовательно sltReadDatagram(), а следовательно не было данных для чтения из сети (не срабатывает readyRead()) - или не так? У меня этот обмен тоже сделан в отдельном потоке (в примере упрощено) - а как это "сигналы не ловлю, просто вычитываю постоянно" - можете дать простейший пример? Наличие данных от программы_1 (работает на компе_1) в программе_2 (работает на компе_2) я проверял именно tcpdump-ом, так как комп_2 работает под ОС Ubuntu (wireshark думаю даст тот же положительный результат)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 17.4.2020, 8:55
Сообщение #4


фрилансер
******

Группа: Участник
Сообщений: 2941
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


KuvshinoF, sltReadDatagram - это у тебя слот, и он по каким-то причинам перестаёт вызываться (точнее - не генерится сигнал)

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

//обработчик таймера
...()
{
    sltReadDatagram();
}


Цитата(KuvshinoF @ 16.4.2020, 16:11) *
можете дать простейший пример


у меня сделано так:
(показано упрощённо)
в потоке, в бесконечном цикле внутри run
QByteArray part;
while(1)
{
    if(UDPServerSocket->state()==QUdpSocket::BoundState)
    {
        auto DatagramSize=UDPServerSocket->bytesAvailable();

        if(DatagramSize>0 && UDPServerSocket->hasPendingDatagrams())
        {
            //DatagramSize - тут неплохо бы ограничить на некий максимальный размер, чтобы не словить краш от нехватки памяти
            //DatagramSize=qMin<decltype(DatagramSize)>(20000,DatagramSize);

            part.resize(DatagramSize);
            const auto readsize=UDPServerSocket->readDatagram(part.data(), part.size(),&host, &port);
            if(readsize>=0)
            {
                part.resize(readsize);
            }
        }
    }

    //part - прочитанные данные
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
KuvshinoF
  опции профиля:
сообщение 17.4.2020, 12:43
Сообщение #5


Студент
*

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

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




Репутация:   0  


Спасибо за советы - обязательно попробую и "подпинывать" свою функцию, и Ваш вариант считывания сетевых данных. Но если это все не поможет, то что в программе может "глушить" сетевой обмен (который, я напоминаю, вначале все-таки идет и внезапно пропадает, хотя tcpdump и простенькая программа считывания данных из сети говорят о продолжении прихода данных от программы_1)? Или если Ваш вариант сетевого считывания поможет, то чем мой хуже? Кстати этот обмен стабильно работает, если сначала запустить программы (1 и 2), а только потом включить (коммутатор) сетевой обмен между ними, хотя по-хорошему порядок запуска программ и включения сетевого обмена должен быть не важен.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 18.4.2020, 8:08
Сообщение #6


фрилансер
******

Группа: Участник
Сообщений: 2941
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


KuvshinoF, выводи в лог последовательность действий и все ошибки, которые можно посмотреть (в частности)

SocketError QAbstractSocket::error() const
SocketState QAbstractSocket::state() const

будет видно, вызывается ли слот вообще

Цитата(KuvshinoF @ 16.4.2020, 16:11) *
У меня этот обмен тоже сделан в отдельном потоке

и покажи, как это сделано, может сообщения потока не обрабатываются ? (QEventLoop)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
KuvshinoF
  опции профиля:
сообщение 18.4.2020, 22:59
Сообщение #7


Студент
*

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

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




Репутация:   0  


У меня так сделано (в упрощенном виде):
class Interaction : public QThread
{
  QUdpSocket oUDPSocket;
  QByteArray baoBufRecv;
  unsigned short  usSendPort;
  QHostAddress haoLocalAddr, haoSenderAddr;
...
}

Interaction::Interaction ()
{
  baoBufRecv.resize(65535);
  haoLocalAddr.setAddress("192.168.235.66");
  oUDPSocket.bind(haoLocalAddr, 5000);
...
}

void Interaction::run()
{
  connect(&oUDPSocket, SIGNAL(readyRead()), this, SLOT(sltReadDatagram()));
  exec();
}

void Interaction::sltReadDatagram()
{
  vReadDatagram(); // описана ранее в первом сообщении темы
}

MainCkass.cpp
Создается указатель на объект Interaction и вызывается его start() с приоритетом QThread::TimeCriticalPriority

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 19.4.2020, 21:21
Сообщение #8


фрилансер
******

Группа: Участник
Сообщений: 2941
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


KuvshinoF, да вроде всё, что нужно имеется. Остаётся выяснить, поможет ли подпинывание слота "вручную". Ну и лог вести
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
KuvshinoF
  опции профиля:
сообщение 20.4.2020, 10:54
Сообщение #9


Студент
*

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

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




Репутация:   0  


Спасибо, буду пробовать, когда предоставится такая возможность.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 20.4.2020, 11:03
Сообщение #10


фрилансер
******

Группа: Участник
Сообщений: 2941
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

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




Репутация:   34  


Цитата(KuvshinoF @ 19.4.2020, 0:59) *
vReadDatagram(); // описана ранее в первом сообщении темы


так а где этот слот находится то ? В потоке или в главном окне? У меня смутные подозрения, что с синхронизацией напутано тут

не вижу вызов moveToThread нигде


Цитата(KuvshinoF @ 19.4.2020, 0:59) *
class Interaction : public QThread
{
  QUdpSocket oUDPSocket;
  QByteArray baoBufRecv;

у тебя рабочий объект и поток - одним классом. Тогда уж лучше унаследоваться от QThread

А в твоём варианте рабочий объект должен быть отдельно от потока. Рабочий объект создаётся в ОСНОВНОМ потоке, настраивается, затем перемещается в контекст потока. Я эту практику недолюбливаю, ей не пользуюсь, поэтому за деталями - в интернет ) Я обычно наследуюсь и не испытываю этот гемор

Сообщение отредактировал Алексей1153 - 20.4.2020, 11:07
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 27.11.2024, 23:03