Russian Qt Forum
Ноябрь 23, 2024, 12:05 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Завершение серверного потока  (Прочитано 8726 раз)
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« : Октябрь 18, 2011, 10:56 »

Доброго дня! Проблема в следующем..
Создаю на каждого подключаемого клиента свой поток
Код:
void FortuneServer::incomingConnection(int socketDescriptor)
 {
     
     QString fortune = fortunes.at(qrand() % fortunes.size());
     FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);
     connect(thread, SIGNAL(msgToGUI(QString,int)), SIGNAL(MessageS(QString,int)));
     
     connect(thread, SIGNAL(finished()), SLOT(deleteLater()));

     thread->start();
 }

Функция потока:
Код:
void FortuneThread::run()
 {
     tcpSocket = new QTcpSocket(this); // для каждого подключенного клиента свой СОКЕТ

     if(!tcpSocket->setSocketDescriptor(socketDescriptor)) {
        emit error(tcpSocket->error());
        emit MessageClient(tcpSocket, "<b>SERVER:</b>Error to initialization Socket!",2);
}
 
while(true)
{
             if(tcpSocket->state() == QAbstractSocket::UnconnectedState)
                     {
        tcpSocket->disconnectFromHost();
                tcpSocket->waitForDisconnected();
return;                                           // ??????!!!!!!!!!!         
       }

if(tcpSocket->waitForReadyRead(3000))
     {
// .... принимаем данные от клиента

     } // waitForReadyRead()

} // while()
}

Собственно вопрос как завершить правильно поток, если клиент отсоединился??! Ибо сейчас, если клиент отсоединился он больше не подключается (не вызывается incomingConnection) ! Если закоментить return, то клиент подключается, но начинает грузиться CPU!
Записан
serega-5508
Гость
« Ответ #1 : Октябрь 18, 2011, 20:54 »

написать функцию проверки соединения. если отключён, то завершать поток. простая проверка при помощи таймера делается.
Записан
andrew.k
Гость
« Ответ #2 : Октябрь 19, 2011, 02:25 »

Код
C++ (Qt)
connect(thread, SIGNAL(finished()), SLOT(deleteLater()));
 
Ты удаляешь не поток, а FortuneServer.
Когда ты комментируешь ретурн, поток просто не может завершиться и поэтом сервер продолжает жить и плодить бессметные потоки.
Правильно:
Код
C++ (Qt)
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
 
Это вообще странный кусок. Первые две строки блока не нужны совершенно. Сокет и так отключен уже.
Код
C++ (Qt)
if(tcpSocket->state() == QAbstractSocket::UnconnectedState)
                    {
       tcpSocket->disconnectFromHost();
               tcpSocket->waitForDisconnected();
return;                                           // ??????!!!!!!!!!!          
    }
 

А вообще ты можешь ловить от сокета сигнал disconnected() но тогда надо делать через exec() внутри run()

К тому же возможно после вызова waitForReadyRead, если произойдет разрыв соединения, не факт, что управление вернется сразу, а по таймауту, т.е. через 3 секунды. Кто знает достоверно прокомментируйте.
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #3 : Октябрь 19, 2011, 11:27 »

connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

Действительно это решило проблему! Огромное спасибо, andrew.k =)

Вроде все работает как и задумывалось.. Клиенты нормально подключаются в отдельных потоках и передают файлы на сервер, нормально и отключаются..! Теперь стоит вопрос в скорости и надежности, а именно:
1. Обнаруживать, что клиент отключился максимально быстро, даже в момент передачи файла и завершить корректно поток, связанный с этим клиентом! После определенного тестирования возникает такая проблемка (не всегда, но пару раз вылетала программа!!!)..
Если скажем 3 клиента передают одновременно файлы большого размера и в момент передачи закрыть одного из клиентов, то при завершении работы сервера вылитала ошибка в файле QObject.cpp:
Код:
QTread *QObject::thread() const
{
   return d_func()->threadData->thread;  // на этой строке вылетала ошибка !!!
}


Чтобы это значило?Непонимающий

2. Принимать файлы большого размера (около 200 Мб) также как можно быстрее! Если есть идеи как можно оптимизировать этот код, подскажите пожалуйста!

Код:
void FortuneThread::run()
 {
     headl objHead;
     IDThr = (int)currentThreadId();

     tcpSocket = new QTcpSocket(this);

     if(!tcpSocket->setSocketDescriptor(socketDescriptor)) {
        emit error(tcpSocket->error());
        emit MessageClient(tcpSocket, "<b>SERVER:</b>Error to initialization Socket!",2);
}
    
        emit MessageClient(tcpSocket, "<b>SERVER:</b>Client was connected!",2);
   emit msgToGUI(QTime::currentTime().toString()+" <b>Client</b> " + QString().setNum(numCl) + " CONNECTED!",2);

   QFile file("MatrixData_" + QString().setNum(IDThr));
   if(file.open(QIODevice::WriteOnly))
    {
while(true)
{
if(tcpSocket->state() == QAbstractSocket::UnconnectedState) {
 delete tcpSocket;
 emit msgToGUI("<b>Client</b> DISCONNECTED!",2);
 
 return;
}

if(tcpSocket->waitForReadyRead(1000))
    {
 if(!flag) // false ; чтение заголовка
 {  
timer.start();
    retrRead = tcpSocket->read((char*)&objHead,sizeof(objHead)); // читаем переданную стуктуру!                                

if( retrRead == -1)  return;
if( retrRead ==  0)  return;
  }
 
     
      if(tcpSocket->bytesAvailable() != objHead.sizeData)
  {
    flag = true;
    continue;
  }

  file.write(tcpSocket->read(objHead.sizeData));

  emit MessageClient(tcpSocket, "<b>\nSize file: </b>" + QString().setNum(objHead.sizeData) + " Byte", 2);
  emit msgToGUI(QTime::currentTime().toString()+" <b>File is sent - </b>" + QString().setNum(timer.elapsed(),10) + " ms",2);
                          
  flag = false;
  file.close();
 
 
} // waitForReadyRead()
} // while()
       }
        else { // если нельзя прочитать файл
 msgToGUI("<b>Error</b> of the determination of the file!",2);
 return;
      }
}
« Последнее редактирование: Октябрь 19, 2011, 12:47 от Vladimir » Записан
andrew.k
Гость
« Ответ #4 : Октябрь 19, 2011, 20:20 »

Сделал бы через eventLoop проще бы было и понятней.

Может местами поменять эти строчки? Не рано ли удалил.
Код
C++ (Qt)
delete tcpSocket;
emit msgToGUI("<b>Client</b> DISCONNECTED!",2);
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #5 : Октябрь 20, 2011, 10:34 »

Сигнал msgToGUI() в принципе не связан с сокетом.. он просто выводит сообщение о дисконекте клиента на форму сервера!Но, если поменять ошибка все равно иногда проскакивает..  В замешательстве и именно, когда закрываешь приложение сервера, а не вовремя отключения/подключения клиентов или передаче файлов..! Непонимающий

// файл QObgect.cpp
QTread *QObject::thread() const
{
   return d_func()->threadData->thread;  // на этой строке вылетала ошибка !!!
}
Записан
andrew.k
Гость
« Ответ #6 : Октябрь 20, 2011, 10:42 »

Неизвестно как у тебя там все организовано. Видимо ты все-таки где-то удаляешь раньше чем нужно.

Кстати
Код
C++ (Qt)
tcpSocket = new QTcpSocket(this);
Убери this. Он не нужен. Вдруг поможет.)
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #7 : Октябрь 20, 2011, 11:20 »

К сожалению не помогло..Даже наоборот, если убрать this, при закрытии приложения процесс остается висеть и грузить дико проц! Кину весь файл, глянь пожалуйста, может заметишь где собака зарыта)

Код:
FortuneServer::FortuneServer() : QTcpServer()
 {
     fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
              << tr("You've got to think about tomorrow.")
              << tr("You will be surprised by a loud noise.")
              << tr("You will feel hungry again in another hour.")
              << tr("You might have mail.")
              << tr("You cannot kill time without injuring eternity.")
              << tr("Computers are not intelligent. They only think they are.");
 
numCl = 0;
 }

bool FortuneServer::InitializeServer(int port)
{
QString nP;
nP.setNum(port);
nPort = port;
if (!listen(QHostAddress::Any, nPort)) {
           QMessageBox::critical(0,"Server Error","Unable to start the server");
           return false;
          }
emit MessageS("TCP-Server is listen <b>Port</b> " + nP,2);
return true;
}


void FortuneServer::incomingConnection(int socketDescriptor)
 {
    
QString fortune = fortunes.at(qrand() % fortunes.size());
     FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);
connect(thread, SIGNAL(msgToGUI(QString,int)), SIGNAL(MessageS(QString,int)));
thread->numCl = ++numCl;
     connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

     thread->start();
 }

// ================================= Thread() ============================================================
// конструктор !
FortuneThread::FortuneThread(int socketDescriptor, const QString &fortune, QObject *parent)
     : QThread(parent), socketDescriptor(socketDescriptor), text(fortune), tcpSocket(NULL)
{
     connect(this, SIGNAL(MessageClient(QTcpSocket*,QString,int)),SLOT(sendToClient(QTcpSocket*,QString,int)));
flag = false;
numCl = 0;
}

void FortuneThread::run()
 {
headl objHead;
     IDThr = (int)currentThreadId();

     tcpSocket = new QTcpSocket(this);

     if(!tcpSocket->setSocketDescriptor(socketDescriptor)) {
        emit error(tcpSocket->error());
        emit MessageClient(tcpSocket, "<b>SERVER:</b>Error to initialization Socket!",2);
}
    
        emit MessageClient(tcpSocket, "<b>SERVER:</b>Client was connected!",2);
   emit msgToGUI(QTime::currentTime().toString()+" <b>Client</b> " + QString().setNum(numCl) + " CONNECTED!",2);


while(!tcpSocket->waitForReadyRead(1))
 {
     if(tcpSocket->state() == QAbstractSocket::UnconnectedState) {
   emit msgToGUI("<b>Client</b> DISCONNECTED!",2);
 delete tcpSocket;
 
 return;
  }
 }

QFile file("MatrixData_" + QString().setNum(IDThr));
if(file.open(QIODevice::WriteOnly))
 {
   while(true)
    {
 
  if(tcpSocket->state() == QAbstractSocket::UnconnectedState) {
     if(file.isOpen()) file.close();
 emit msgToGUI("<b>Client</b> DISCONNECTED!",2);
 delete tcpSocket;
   
 return;
  }

  if(tcpSocket->waitForReadyRead(1000))
    {
   if(!flag) // false
    {  
timer.start();
    retrRead = tcpSocket->read((char*)&objHead,sizeof(objHead)); // читаем переданную стуктуру!                                

if( retrRead == -1)  return;
if( retrRead ==  0)  return;
    }

   if(tcpSocket->bytesAvailable() != objHead.sizeData)
{
  flag = true;
      continue;
    }

   file.write(tcpSocket->read(objHead.sizeData));

   emit MessageClient(tcpSocket, "<b>\nSize file: </b>" + QString().setNum(objHead.sizeData) + " Byte", 2);
emit msgToGUI(QTime::currentTime().toString()+" <b>File is sent - </b>" +  QString().setNum(timer.elapsed(),10) + " ms",2);
                          
flag = false;
file.close();
 
  } // waitForReadyRead()
   } // while()
     } // if() file.open()
else
{   // если нельзя открыть файл
    msgToGUI("<b>Error</b> of the determination of the file!",2);
    return;
}
} // run()

void FortuneThread::sendToClient(QTcpSocket* pSocket, QString str, int num) // отправить Клиенту
{
    QByteArray  arrBlock;

headl objHeadSendCl;
objHeadSendCl.sizeData = str.size();

arrBlock.append((const char*)&objHeadSendCl, sizeof(objHeadSendCl));
arrBlock.append(str);
  
    pSocket->write(arrBlock);
}

Главная форма:

Код:
FormServ::FormServ(QWidget *parent) : QDialog(parent)
{
   setupUi(this); // инициализация формы

   editServ->setFocus();
   QRegExp regExp("[0-9]{1,5}"); // ограниченный ввод данных
   editServ->setValidator(new QRegExpValidator(regExp,this));
  
   connect(butServ, SIGNAL(clicked()), SLOT(lineEd_textPORT()));
  
   m_Serv = new FortuneServer;
  
   connect(m_Serv, SIGNAL(MessageS(QString,int)), SLOT(slotShowMessage(QString,int)));
};

void FormServ::lineEd_textPORT()
{
 bool ok;
      m_Serv->InitializeServer(editServ->text().toInt(&ok,10));
}

void FormServ::slotShowMessage(QString mess,int id)
{
if(id == 2) textEditServ->append(mess);
    
}
« Последнее редактирование: Октябрь 20, 2011, 11:35 от Vladimir » Записан
andrew.k
Гость
« Ответ #8 : Октябрь 20, 2011, 11:35 »

Слушай, это же пример из ассистанта?
Как ты умудрился его сломать?)
Threaded Fortune Server
Сравни с оригиналом. Найди ошибку.
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #9 : Октябрь 20, 2011, 11:43 »

Так да оттуда, не хочется изобретать велосипед!) то что там описано: подключение клиентов в отдельном потоке реализовано и у меня, и это работает! Я же ничего не менял глобально.. а вот отключение клиентов и завершение работы этих потоков там не приводится, писал сам! Может в этом проблема.. Что вообще эта ошибка означает??
Записан
andrew.k
Гость
« Ответ #10 : Октябрь 20, 2011, 11:45 »

Дико грузит проц думаю из-за этого.

Код
C++ (Qt)
while(!tcpSocket->waitForReadyRead(1))
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #11 : Октябрь 20, 2011, 11:50 »

Дико грузит проц думаю из-за этого.

Код
C++ (Qt)
while(!tcpSocket->waitForReadyRead(1))

Да вроде вообще не грузит (1%).. Согласен может и не самое удачное решение (другого не нашел).. иначе бы сразу создавался файл при подключении, даже без передачи, а это тоже не есть правильно! Или имеешь ввиду после закрытия приложения, но предполагается, что все потоки должны быть к этому времени завершены..
« Последнее редактирование: Октябрь 20, 2011, 11:53 от Vladimir » Записан
masherbober
Гость
« Ответ #12 : Январь 27, 2013, 00:20 »

Бодрого времени суток! Запускаю проект threaded fortune server и fortune client, клиент находит IP, который выдает сервер, но при подключении к порту выдает ошибку - Connection timed out - что нужно настроить, подскажите пожалуйста!
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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