crossplatform.ru

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

 
Ответить в данную темуНачать новую тему
> QTcpSocket и QTcpServer, Проблема с поддержанием соединения
belirafor
  опции профиля:
сообщение 13.12.2011, 1:21
Сообщение #1


Новичок


Группа: Новичок
Сообщений: 3
Регистрация: 9.12.2011
Пользователь №: 3051

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




Репутация:   0  


Здравствуйте, уважаемые у частники форума. Пишу контрольную работу "Клиент-сервер". Суть проблемы:
  1. Запускаю сервер
  2. Запускаю клиент
  3. Клиент передает серверу некоторую информацию
  4. Сервер ее обрабатывает и возвращает клиенту результат в поле tableWidget
  5. Нажимаю на клиенте кнопку "Обновить" и поля tableWidget очистились.


Очищаются они потому, что я использую tcpSocket->close() и на сервере и на клиенте после выполнения приема/передачи данных. Если же я не использую tcpSocket->close(), то получается:
  1. запуск сервера
  2. запускаю клиента
  3. Клиент запущен (где-то в памяти), однако окно не появляется у меня на экране.


Подскажите, как сделать так, чтобы клиент не повисал после запуска. В общем как мне обойтись без tcpSocket->close() после передачи данных. Поскольку мне нужно выводить информацию о подключаемых клиентах на сервере. А если буду каждый раз инициировать соединение со стороны клиента, тогда будет путаница.

Скажу сразу - я плохо разбираюсь в программировании, в силу того что не работаю по специальности (а с сокетами вообще никогда не имел дела). Посмотреть примеры из Qt creator не предлагайте. Смотрел много раз Threaded Fortune Server Example и Client Example.

Ниже привожу код клиента и сервера, а так же ссылку на Cyberforum, где расположена моя тема
/*Клиент*/
//mainwindow.cpp

void MainWindow::fncJournal_Refresh()
{
    QTextCodec *codec = QTextCodec::codecForName("UTF-8");  //Указываем кодировку явным обрзом

    QByteArray SendKey = ("qryJrnl_SELECT");
    tcpSocket->write(SendKey);                  //Отправляем серверу задание для выполнения запроса

    tcpSocket->waitForReadyRead();
    tcpSocket->readAll();                       //Ждем ответа от сервера о готовности

    QByteArray qryJrnl_SELECT = ("SELECT pkJrnlID, NameJrnl  FROM rJrnl_tbl ORDER BY NameJrnl DESC");
    tcpSocket->write(qryJrnl_SELECT);


    QTableWidgetItem *newItem;
    ui->tblwgt_Journal->setRowCount(0);
    ui->tblwgt_Journal->setSortingEnabled(true);

    do
    {
        tcpSocket->waitForReadyRead();
        qint32 sl_pkJrnlID;                                     //Длина принимаемой строки, sl - String Length
        tcpSocket->read((char*) &sl_pkJrnlID,4);                //Читаем длину строки, от сервера
        QByteArray pkJrnlID = tcpSocket->read(sl_pkJrnlID);     //Читаем, ТОЛЬКО, необходимое количество байт, чтобы отделить pkJrnlID от NameJrnl
//        qDebug() << pkJrnlID;

        tcpSocket->waitForReadyRead();
        qint32 sl_NameJrnl;
        tcpSocket->read((char*) &sl_NameJrnl,4);
        QByteArray NameJrnl = tcpSocket->read(sl_NameJrnl);
        QString u_NameJrnl = codec->toUnicode(NameJrnl);        //Указываем кодировку, явным образом, чтобы избежать проблем при отображении кириллицы
//        qDebug() << u_NameJrnl;

        ui->tblwgt_Journal->insertRow(0);
        newItem = new QTableWidgetItem();newItem->setText(pkJrnlID);
        ui->tblwgt_Journal->setItem(0,0, newItem);
        newItem = new QTableWidgetItem();newItem->setText(u_NameJrnl);
        ui->tblwgt_Journal->setItem(0,1, newItem);
    }while(tcpSocket->bytesAvailable() != 0);

    tcpSocket->close();

    ui->tblwgt_Journal->hideColumn(0);
    ui->tblwgt_Journal->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
    ui->tblwgt_Journal->horizontalHeader()->setStretchLastSection(true);
    ui->tblwgt_Journal->verticalHeader()->setHidden(true);

    int RowCnt = ui->tblwgt_Journal->rowCount();

    if(RowCnt == 0) {ui->statusBar->showMessage(tr("Записей в базе: 0"));}

    else {ui->statusBar->showMessage(tr("Записей в базе: ") + QString::number(RowCnt));}
    fncConnect();       //После закрытия сокета инициируем соединение по новой
}

void MainWindow::fncConnect()
{
    tcpSocket = new QTcpSocket(this);
    tcpSocket->connectToHost("localhost", 3333);
}


/*Сервер*/
#include "dlginfo.h"
#include "ui_dlginfo.h"

DlgInfo::DlgInfo(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DlgInfo)
{
    ui->setupUi(this);
//    setWindowTitle(QString::fromUtf8("Сервер"));
    setWindowTitle(tr("Сервер"));

    StartServer();

    connect(ui->pbtn_Start, SIGNAL(clicked()), SLOT(StartServer()));
    connect(ui->pbtn_Stop, SIGNAL(clicked()), SLOT(StopServer()));
}

void DlgInfo::StartServer()
{
    tcpServer = new QTcpServer(this);

    if(!tcpServer->listen(QHostAddress::Any, 3333))
    {
        ui->txtbrsr_Info->append(tcpServer->errorString());
    }

    else
    {
        connect(tcpServer, SIGNAL(newConnection()), SLOT(AcceptConn()));
        ui->txtbrsr_Info->append(tr("Сервер запущен"));
        ui->pbtn_Start->setDisabled(true);
    }
}

void DlgInfo::StopServer()
{
    tcpServer->close();
    ui->txtbrsr_Info->append(tr("Сервер остановлен"));
    ui->pbtn_Start->setEnabled(true);
}

//void DlgInfo::NewIncConn()
//{
//    //Информация о подключаемых клиентах
//    ui->txtbrsr_Info->append(tr("Входящее соединение"));
//}

void DlgInfo::AcceptConn()
{
//    NewIncConn();
    tcpSocket = tcpServer->nextPendingConnection();
    connect(tcpSocket, SIGNAL(readyRead()), SLOT(IncKey()));
}

void DlgInfo::IncKey()
{
        QByteArray Key = tcpSocket->readAll();

        if(Key == "qryJrnl_SELECT")
        {
            JrnlRefresh();
            ui->txtbrsr_Info->append(tr("Обновили данные окна"));
            return;
        }
}

void DlgInfo::JrnlRefresh()
{
    tcpSocket->write("Ready");                          //Отправляем клиенту сообщение о готовности

    tcpSocket->waitForReadyRead();
    QByteArray JrnlSelect = tcpSocket->readAll();       //Считали строку запроса целиком

    QSqlQuery qryJrnl_SELECT;
    qryJrnl_SELECT.exec(JrnlSelect);
    qryJrnl_SELECT.next();

    do{
        QByteArray pkJrnlID = qryJrnl_SELECT.value(0).toByteArray();
        QString NameJrnl = qryJrnl_SELECT.value(1).toString();

        qint32 sl_pkJrnlID = pkJrnlID.size();           //Получаем длину строки, передаваемой клиенту. Делаем для разделения данных, чтобы не пришла "каша"
        tcpSocket->write((char*) &sl_pkJrnlID,4);       //Передаем длину строки клиенту
        tcpSocket->write(pkJrnlID);                     //Передаем id журнала клиенту

        qint32 sl_NameJrnl = NameJrnl.toUtf8().size();  //Снова получаем длину строки и не забываем, что передаем ее в utf8, иначе придет "каша"
        tcpSocket->write((char*) &sl_NameJrnl,4);       //Передаем длину строки клиенту
        tcpSocket->write(NameJrnl.toUtf8().data());     //Передаем наименование журнала

//        qDebug() << pkJrnlID << NameJrnl;

    }while(qryJrnl_SELECT.next());     //Выполняем запрос до тех пор пока не закончатся данные
    tcpSocket->close();
}

DlgInfo::~DlgInfo()
{
    tcpServer->close();
    delete ui;
}


Заранее, спасибо.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
belirafor
  опции профиля:
сообщение 18.12.2011, 23:39
Сообщение #2


Новичок


Группа: Новичок
Сообщений: 3
Регистрация: 9.12.2011
Пользователь №: 3051

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




Репутация:   0  


Тут вообще, кто-нибудь обитает?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ssoft
  опции профиля:
сообщение 19.12.2011, 7:12
Сообщение #3


Участник
**

Группа: Участник
Сообщений: 130
Регистрация: 17.2.2010
Из: Москва
Пользователь №: 1470

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




Репутация:   3  


Цитата(belirafor @ 19.12.2011, 0:39) *
Тут вообще, кто-нибудь обитает?


Иногда ))).

Проблема , в том, что Вы исользуете waitForReadyRead() - метод, который останавливает основной поток и соотвно графическое отображение таблицы.

Нужно у MainWindow завести slot, например, onSocketRead(), связать его с сокетом

connect( waitForReadyRead(), SIGNAL( readyRead() ), this, SLOT( onSocketRead() ) );


и перенести функционал по считыванию данных туда, и никаких waitForReadyRead().

С множеством клиентов немного посложнее.
Я бы для каждого подключения организовал свой class ServerDelegate : public QObject; в котором бы реализовал логику клиент-серверного взаимодействия со стороны клиента.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 29.3.2024, 15:35