Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Exception при отправке ответа через сокет 
:(
    Опции темы
niklep
Дата 28.4.2011, 07:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Доброго времени суток. Есть слот, связанный с сигналом:
Код

connect(clientSocket, SIGNAL(readyRead()),
                this, SLOT(slotReadClient())); // при поступлении запросов от клиентов

Вот этот слот:
Код

void ServerSocket::slotReadClient()
{
        connect(temp_com->port, SIGNAL(readyRead()), this, SLOT(slotReadCom())); // связь с COM-портом
 
        QTcpSocket* clientSocket = (QTcpSocket*)sender();
        QDataStream in(clientSocket);
        in.setVersion(QDataStream::Qt_4_5);
        for (;;)
        {
                if (!m_nNextBlockSize)
                {
                        if (clientSocket->bytesAvailable() < sizeof(quint16))
                                break;
                        in >> m_nNextBlockSize;
                }
                if (clientSocket->bytesAvailable() < m_nNextBlockSize)
                        break;
                QTime time;
                QString str="";
                in >> time >> str;
                str += "\r";
                QByteArray ba = str.toUtf8(); // переводим QString
                char *str2 = ba.data(); // в char
                qDebug() << "STR2: " << "'" << str2 << "'";
                m_nNextBlockSize=0;
                temp_com->writeToPort(str2);
        }
}

Его суть проста: при появлении данных на серверном сокете он вызывается, принимает их. После приема этих данных происходит их отправка на COM-порт с помощью метода  temp_com->writeToPort(str2);
Т.е. суть следующая: на сокет приходит команда, она отправляется COM-порту. Далее ждем ответа от COM-порта:
Код

connect(temp_com->port, SIGNAL(readyRead()), this, SLOT(slotReadCom())); // связь с COM-портом

И как только появляется ответ вызываем нужный слот:
Код

void ServerSocket::slotReadCom()
{
        qba = temp_com->readFromPort();
        qDebug() << "Slot Read: " << qba;
        qDebug() << "Count of bytes Readed: " << qba.size();
        sendToClient(clientSocket, qba); // вот здесь бросается exception. без этой строки не бросается.
}


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

Это сообщение отредактировал(а) niklep - 28.4.2011, 07:27
PM MAIL   Вверх
borisbn
Дата 28.4.2011, 08:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



показывай sendToClient
и чему равен clientSocket в slotReadCom ?

Это сообщение отредактировал(а) borisbn - 28.4.2011, 09:22


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
math64
Дата 28.4.2011, 08:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 23
Всего: 72



а откуда берёте clientSocket в slotReadCom? sender здесь будет temp_com->port.
sender пользоваться не рекомендуется, лучше при появлении клиента создать класс ClientReader (отдельный экземляр на кождого клиента), который будет хранить clientSocket и получать сигналы. ну и конечно, нужно знать что делает sendToClient

Это сообщение отредактировал(а) math64 - 28.4.2011, 08:51
PM   Вверх
niklep
Дата 28.4.2011, 10:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



[offtop]
Гребаный IE9... Написал пост, нажал отправить, а осел почему-то его не отправил... Пишу заново
[\offtop]

Код

void ServerSocket::sendToClient(QTcpSocket* pSocket, const QByteArray str)
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly); // так как мы не знаем размер блока, а этот размер должен быть в самом начале блока, то делаем трюк.
    out.setVersion(QDataStream::Qt_4_5);
    out << quint16(0) << QTime::currentTime() << str; // сначала записываем в первое поле 0, а потом, после того, как известен размер всего блока,

    out.device()->seek(0); // перемещаем указатель на начало блока
    out << quint16(arrBlock.size() - sizeof(quint16)); // и записываем туда размер

    pSocket->write(arrBlock);
}


clientSocket в slotReadCom берется как поле класса:
Код

class ServerSocket : public QTcpServer
{
    Q_OBJECT
public:
    ServerSocket(int nPort, ComHandler *com);
private:
    ComHandler *temp_com;
    QByteArray qba;
    QTcpServer* tcpServer;
    QTcpSocket* clientSocket;
    quint16 m_nNextBlockSize; // хранит в себе длину следующего полученного от сокета блока
    void sendToClient(QTcpSocket* pSocket, const QByteArray str);

private slots:
    void slotNewConnection();
    void slotReadClient();
    void slotReadCom();

};


Честно говоря, всю работу с сетью я взял из учебников по Qt и особо не вдавался в подробности, почему используется именно конструкция
Код

QTcpSocket* clientSocket = (QTcpSocket*)sender();

и как сделать иначе. Просто на маленьком учебном проекте данные методы работали. Сильно не пинайте, я кодить ООП начал месяц назад.
PM MAIL   Вверх
borisbn
Дата 28.4.2011, 10:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



в функции void ServerSocket::slotReadClient() ты объявляешь локальную переменную clientSocket
Цитата(niklep @  28.4.2011,  07:21 Найти цитируемый пост)
  QTcpSocket* clientSocket = (QTcpSocket*)sender();

а переменную член класса с тем же именем ничем не инициализируешь. сделай так
Код

void ServerSocket::slotReadClient()
{
        connect(temp_com->port, SIGNAL(readyRead()), this, SLOT(slotReadCom())); // связь с COM-портом
 
        //QTcpSocket* clientSocket = (QTcpSocket*)sender();
        clientSocket = (QTcpSocket*)sender();
...
и т.д. по тексту
}


Добавлено через 1 минуту и 29 секунд
Цитата(niklep @  28.4.2011,  10:35 Найти цитируемый пост)
Гребаный IE9... Написал пост, нажал отправить, а осел почему-то его не отправил... Пишу заново

Даже не знаю, стОит ли советовать зарезать ишака и взять что-нибудь покошернее - лису или оперу... smile


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
niklep
Дата 28.4.2011, 10:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Действительно, помогло. Сказывается недостаточные теоретические знания. Спасибо.
Правда он ничего мне не отправил=)

P.S. Естественно, пользуюсь постоянно лисой, но вдруг возникла мысль: "А дай-ка я несколько минут опробую новый IE. Вдруг он не так плох?..." =)
PM MAIL   Вверх
borisbn
Дата 28.4.2011, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



стоп! у тебя ж зацикливание получается:
1. Направляем данные из clientSocket в slotReadClient()
Код

connect( clientSocket, SIGNAL(readyRead()), this, SLOT(slotReadClient()) );

2. В slotReadClient() запоминаем от кого пришли данные
Код

clientSocket = (QTcpSocket*)sender();

3. Направляем эти данные в COM
Код

temp_com->writeToPort(str2);

4. Направляем данные, принятые из COM в slotReadCom()
Код

connect(temp_com->port, SIGNAL(readyRead()), this, SLOT(slotReadCom()));

5. В slotReadCom() отправляем данные кому ? clientSocket'ту
Код

        sendToClient(clientSocket, qba);



Скажи, как изначально инициализируется clientSocket ? Где ты делаешь
Код

connect(clientSocket, SIGNAL(readyRead()), this, SLOT(slotReadClient())); 

?
А лучше скинь весь проект.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
math64
Дата 28.4.2011, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 23
Всего: 72



так будет работать, если клиент один.
Если же пока ком-порт не ответил, придет запрос от другого клиента, clientSocket затрётся и ответ для первого клиента получит второй.
Поскольку ком-порт один, второго клиента нужно либо игнорировать, или ставить в очередь например, храня сокеты поставленных в очередь клиентов в QList<QTcpSocket*> или QList<QPair<QTcpSocket*, QByteArray> > если вместе с сокетом нужно хранить принятые от него данные.
PM   Вверх
niklep
Дата 28.4.2011, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Тот самый connect я делаю здесь:
Код

void ServerSocket::slotNewConnection()
{
    QTcpSocket* clientSocket = tcpServer->nextPendingConnection(); // для подтверждения соединения с клиентом
                                // возвращает сокет для связи с клиентом
    qDebug() << "New Connection Detected";
    connect(clientSocket, SIGNAL(disconnected()),
        clientSocket, SLOT(deleteLater()));
    connect(clientSocket, SIGNAL(readyRead()),
        this, SLOT(slotReadClient())); // при поступлении запросов от клиентов
    sendToClient(clientSocket, "Server Response: Connected!"); // отправляем клиенту уведомление
}

И да, как мне его здесь инициализировать? Также? Наверное стоит здесь сделать
Код

clientSocket = tcpServer->nextPendingConnection();

Короче я запутался=)
Весь проект весит много (25Мб). Давай я сюда кину полностью эти 2 класса (ServerSocket и ComHandler). Посмотрим их.

Добавлено через 3 минуты и 43 секунды
serversocket.h
Код

#ifndef SERVERSOCKET_H
#define SERVERSOCKET_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <comhandler.h>

class ServerSocket : public QTcpServer
{
    Q_OBJECT
public:
    ServerSocket(int nPort, ComHandler *com);

private:
    ComHandler* temp_com;
    QByteArray qba;
    QTcpServer* tcpServer;
    QTcpSocket* clientSocket;
    quint16 m_nNextBlockSize; // хранит в себе длину следующего полученного от сокета блока
    void sendToClient(QTcpSocket* pSocket, const QByteArray str);

private slots:
    //virtual void slotNewConnection();
    void slotNewConnection();
    void slotReadClient();
    void slotReadCom();

};

#endif // SERVERSOCKET_H


serversocket.cpp
Код

#include <serversocket.h>

ServerSocket::ServerSocket(int nPort, ComHandler *com)
    : m_nNextBlockSize(0)
{
    temp_com = com;
    tcpServer = new QTcpServer(this);
    if (!tcpServer->listen(QHostAddress::Any, nPort))
    {
        qDebug() << "Unable to start Server: " << tcpServer->errorString();
        tcpServer->close();
        return;
    }
    connect(tcpServer, SIGNAL(newConnection()),
        this, SLOT(slotNewConnection())); // слот вызывается при каждом присоединении нового клиента
    qDebug() << "TCPSocket listen on port" << tcpServer->serverPort();
}

void ServerSocket::slotNewConnection()
{
    clientSocket = tcpServer->nextPendingConnection(); // для подтверждения соединения с клиентом
                                // возвращает сокет для связи с клиентом
    qDebug() << "New Connection Detected";
    connect(clientSocket, SIGNAL(disconnected()),
        clientSocket, SLOT(deleteLater()));
    connect(clientSocket, SIGNAL(readyRead()),
        this, SLOT(slotReadClient())); // при поступлении запросов от клиентов
    sendToClient(clientSocket, "Server Response: Connected!"); // отправляем клиенту уведомление
}

void ServerSocket::slotReadClient()
{
    connect(temp_com->port, SIGNAL(readyRead()), this, SLOT(slotReadCom()));

    //QTcpSocket* clientSocket = (QTcpSocket*)sender();
    QTcpSocket* clientSocket = (QTcpSocket*)sender();
    QDataStream in(clientSocket);
    in.setVersion(QDataStream::Qt_4_5);
    for (;;)
    {
        if (!m_nNextBlockSize)
        {
            if (clientSocket->bytesAvailable() < sizeof(quint16))
                break;
            in >> m_nNextBlockSize;
        }
        if (clientSocket->bytesAvailable() < m_nNextBlockSize)
            break;
        QTime time;
        QString str="";
        in >> time >> str;
        str += "\r";
        QByteArray ba = str.toUtf8(); // переводим QString
        char *str2 = ba.data(); // в char
        qDebug() << "STR2: " << "'" << str2 << "'";
        m_nNextBlockSize=0;
        temp_com->writeToPort(str2);
    }
}

void ServerSocket::slotReadCom()
{
    qba = temp_com->readFromPort();
    qDebug() << "Slot Read: " << qba;
    qDebug() << "Count of bytes Readed: " << qba.size();
    sendToClient(clientSocket, qba);
    qba.clear();
}

void ServerSocket::sendToClient(QTcpSocket* pSocket, const QByteArray str)
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly); // так как мы не знаем размер блока, а этот размер должен быть в самом начале блока, то делаем хак.
    out.setVersion(QDataStream::Qt_4_5);
    out << quint16(0) << QTime::currentTime() << str; // сначала записываем в первое поле 0, а потом, после того, как известен размер всего блока,

    out.device()->seek(0); // перемещаем указатель на начало блока
    out << quint16(arrBlock.size() - sizeof(quint16)); // и записываем туда размер

    pSocket->write(arrBlock);
}


comhandler.h
Код

#ifndef COMHANDLER_H
#define COMHANDLER_H
#include <QObject>
#include <abstractserial.h>
#include <xmlhandler.h>


class ComHandler : public QObject
{
    Q_OBJECT

public:
    ComHandler(XMLHandler *handler);
    ~ComHandler();
    //QString getQba();
    bool err;
    void writeToPort(const char *str);
    QByteArray readFromPort();
    AbstractSerial *port;

//private slots:
   // void slotRead();

private:
    int readBytes;
    QByteArray qba;
    QString s;
};

#endif // COMHANDLER_H


comhandler.cpp
Код

#include <comhandler.h>
#include <QDebug>
#include <QString>
//using namespace std;

ComHandler::ComHandler(XMLHandler *handler)
{
    qDebug() << "Create ComPort";
    err=false;
    port = new AbstractSerial(this);

    //connect(port, SIGNAL(readyRead()), this, SLOT(slotRead())); // СВЯЗЫВАЕМ СИГНАЛ/СЛОТ

    port->setDeviceName(handler->getComPort());

    if (!port->open(AbstractSerial::ReadWrite | AbstractSerial::Unbuffered))
    {
        qDebug() << "Serial device: " << port->deviceName() << " open fail";
        err=true;
        return;
    }

    if (!port->setBaudRate(AbstractSerial::BaudRate9600))
    {
        qDebug() << "Set baud rate " <<  AbstractSerial::BaudRate9600 << " error.";
        err=true;
        return;
    };

    if (!port->setDataBits(AbstractSerial::DataBits8))
    {
        qDebug() << "Set data bits " <<  AbstractSerial::DataBits8 << " error.";
        err=true;
        return;
    }

    if (!port->setParity(AbstractSerial::ParityNone))
    {
         qDebug() << "Set parity " <<  AbstractSerial::ParityNone << " error.";
         err=true;
         return;
    }

    if (!port->setStopBits(AbstractSerial::StopBits1))
    {
        qDebug() << "Set stop bits " <<  AbstractSerial::StopBits1 << " error.";
        err=true;
        return;
    }

    if (!port->setFlowControl(AbstractSerial::FlowControlOff))
    {
        qDebug() << "Set flow " <<  AbstractSerial::FlowControlOff << " error.";
        err=true;
        return;
    }

    // Here set total timeout for read 1 ms, if open mode is Unbuffered only!
#if defined (Q_OS_UNIX)
    // Method setTotalReadConstantTimeout() not supported in *.nix.
    if (port->openMode() & AbstractSerial::Unbuffered)
        port->setCharIntervalTimeout(5000);//5 msec
#elif defined (Q_OS_WIN)
    if (port->openMode() & AbstractSerial::Unbuffered)
        port->setTotalReadConstantTimeout(100);
#endif


    //Here, the new set parameters (for example)
    qDebug() << "= New parameters =";
    qDebug() << "Device name: " << port->deviceName();
    qDebug() << "Baud rate: " << port->baudRate();
    qDebug() << "Data bits: " << port->dataBits();
    qDebug() << "Parity: " << port->parity();
    qDebug() << "Stop bits: " << port->stopBits();
    qDebug() << "Flow: " << port->flowControl();
    qDebug() << "Total read timeout constant, msec: " << port->totalReadConstantTimeout();
    qDebug() << "Char interval timeout, usec: " << port->charIntervalTimeout();
    
}

ComHandler::~ComHandler()
{
    port->close();
}

QByteArray ComHandler::readFromPort()
{
    return port->readAll();
}

void ComHandler::writeToPort(const char *str)
{
    qint64 bw = 0; //count of bytes really writed
    bw = port->write(str);
    qDebug() << "Count of bytes writed: " << bw;
    qDebug() << "Writed info: " << "'" << str << "'";
    //str="";



Добавлено через 6 минут и 40 секунд
Цитата(math64 @  28.4.2011,  11:14 Найти цитируемый пост)
так будет работать, если клиент один.

Так да, но у меня задумано (по крайней мере пока что), что с одной железкой будет работать только один пользователь. Данный проект - это виндовая служба, и если понадобится, то для другого человека цепляется другая железка и запускается новая служба, которая с другим COM-портом общается.
PM MAIL   Вверх
borisbn
Дата 28.4.2011, 13:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Цитата(niklep @  28.4.2011,  11:18 Найти цитируемый пост)

И да, как мне его здесь инициализировать? Также? Наверное стоит здесь сделать
clientSocket = tcpServer->nextPendingConnection();

в данном случае всё равно. ты либо создашь локальную переменную, законнектишь её сигнал на слот, в котором получишь этот указатель через sender() и запомнишь в члене класса clientSocket, либо сразу запомнишь при новом соединении.

Цитата(niklep @  28.4.2011,  10:49 Найти цитируемый пост)
Действительно, помогло. Сказывается недостаточные теоретические знания. Спасибо.Правда он ничего мне не отправил=)

может теперь проблема в клиенте ?



--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
niklep
Дата 28.4.2011, 14:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Привожу код клиента. Также приведу код сервера (данные клиент и сервер я изначально написал для тестов и для обучения).

КЛИЕНТ (хотел сделать его многопоточным для нормальной работы GUI, но пока не осилил=))
client.h
Код

#ifndef CLIENT_H
#define CLIENT_H

#include <QtGui/QWidget>
#include <QTcpSocket>
#include <mythread.h>

class QTextEdit;
class QLineEdit;
class MyThread;

class Client : public QWidget
{
    Q_OBJECT
private:
    QLineEdit* txtInput;
    quint16 nextBlockSize;
    QTextEdit* txtInfo;
    MyThread* timerThread;

public:
    Client(const QString& strHost, int nPort, QWidget *parent = 0, Qt::WFlags flags = 0);
    QString host;
    int port;
    QTcpSocket* tcpSocket;

private slots:
    void slotReadyRead ();
    void slotError (QAbstractSocket::SocketError);
    void slotSendToServer();
    void slotConnected();
};

#endif // CLIENT_H


client.cpp
Код

#include <client.h>
#include <mythread.h>
#include <QtGui>
#include <QtNetwork>
#include <QtSql>

Client::Client(const QString& strHost, int nPort, QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags), nextBlockSize(0)
{
    txtInfo = new QTextEdit;
    txtInput = new QLineEdit;
    txtInfo->setReadOnly(true);
    QPushButton* pcmd = new QPushButton("Send");
    QVBoxLayout* pvbxLayout = new QVBoxLayout;
    pvbxLayout->addWidget(new QLabel("<H1>Client</H1>"));
    pvbxLayout->addWidget(txtInfo);
    pvbxLayout->addWidget(txtInput);
    pvbxLayout->addWidget(pcmd);
    setLayout(pvbxLayout);
    
    host = strHost;
    port = nPort;
    tcpSocket = new QTcpSocket(this);
    timerThread = new MyThread(this, this);
    timerThread->run();

    connect(tcpSocket, SIGNAL(connected()),
             SLOT(slotConnected()));
    connect(tcpSocket, SIGNAL(readyRead()),
             SLOT(slotReadyRead()));
    connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
             this, SLOT(slotError(QAbstractSocket::SocketError)));
    connect(pcmd, SIGNAL(clicked()),
             SLOT(slotSendToServer()));
    connect(txtInput, SIGNAL(returnPressed()),
        this, SLOT(slotSendToServer()));
}

void Client::slotReadyRead()
{
    QDataStream in(tcpSocket);
    in.setVersion(QDataStream::Qt_4_5);
    
    for (;;)
    {
        if (!nextBlockSize)
        {
            if (tcpSocket->bytesAvailable() < sizeof(quint16))
                break;
            in >> nextBlockSize;
        }
        if (tcpSocket->bytesAvailable() < nextBlockSize)
            break;
        QTime time;
        QString str;
        in >> time >> str;
        
        qDebug() << str;
        txtInfo->append(time.toString() + " " + str);
        nextBlockSize = 0;
    }
}

void Client::slotError(QAbstractSocket::SocketError err)
{
    QTime time;

    QString strError = time.currentTime().toString() + " Error: ";
    if (err==QAbstractSocket::HostNotFoundError)
    {
        strError = strError + "The host was not found";
    }
    else if (err==QAbstractSocket::RemoteHostClosedError)
    {
        strError = strError + "The remote host is closed";
    }
    else if (err==QAbstractSocket::ConnectionRefusedError)
    {
        strError = strError + "The Connection was refused";
    }
    else
    {
        strError = strError + tcpSocket->errorString();
    }
    txtInfo->append(strError);

    
    if (timerThread->getStopped()) // вот здесь потенциальное место ошибки (почему? смотри предыдущую строчку - так по идее должно быть)
    {
        timerThread = new MyThread(this, this);
        timerThread->run();
    }
}

void Client::slotSendToServer()
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_5);
    out << quint16(0) << QTime::currentTime() << txtInput->text(); // сначала записываем в первое поле 0, а потом, после того, как известен размер всего блока,

    out.device()->seek(0); // перемещаем указатель на начало блока
    out << quint16(arrBlock.size() - sizeof(quint16)); // и записываем туда размер

    tcpSocket->write(arrBlock); // пишем блок в сокет (почему пишем не out???)
    txtInput->setText("");
}

void Client::slotConnected()
{
    QTime time;
    QString mess = time.currentTime().toString()+" Received the connected signal";
    txtInfo->append(mess);
}

mythread.h
Код

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QtGui/QWidget>
#include <client.h>
#include <QTimer>

class Client;

class MyThread : public QThread
{
    Q_OBJECT

public:
    MyThread(QObject *parent, Client *some_client);
    void run();
    void stop();
    bool getStopped();
    void setStoppedToFalse();

private:
    QTimer* tcpTimer;
    Client *temp_client;
    volatile bool stopped;
    volatile bool timerExist;

private slots:
    void slotConnectToHost();
};
#endif // MYTHREAD_H


mythread.cpp
Код

#include <mythread.h>
#include <client.h>
#include <QtGui/QWidget>

MyThread::MyThread(QObject *parent, Client *some_client)
    : QThread(parent)
{
    qDebug() << "New Thread";
    temp_client = some_client;
    stopped = false;
    timerExist = false;
}

void MyThread::setStoppedToFalse()
{
    stopped = false;
}
bool MyThread::getStopped()
{
    return stopped;
}

void MyThread::run()
{
    if (!stopped)
    {
        qDebug() << "Thread RUN";
        if (!timerExist)
        {
            tcpTimer = new QTimer(this);
            //tcpTimer->moveToThread(this);
            connect(tcpTimer, SIGNAL(timeout()), SLOT(slotConnectToHost()), Qt::DirectConnection);
            timerExist = true;
        }
        tcpTimer->start(5000);
    }
}

void MyThread::stop()
{
    qDebug() << "Thread STOP";
    tcpTimer->stop();
    stopped=true;
}

void MyThread::slotConnectToHost()
{
    temp_client->tcpSocket->connectToHost(temp_client->host,temp_client->port);
    if (temp_client->tcpSocket->waitForConnected())
        this->stop();
}


СЕРВЕР
server.h
Код

#ifndef SERVER_H
#define SERVER_H

#include <QtGui/QWidget>

class QTcpServer;
class QTcpSocket;
class QTextEdit;

class Server : public QWidget
{
    Q_OBJECT

private:
    QTcpServer* tcpServer;
    QTextEdit* txt;
    quint16 m_nNextBlockSize; // хранит в себе длину следующего полученного от сокета блока

public:
    Server(int nPort, QWidget *parent = 0, Qt::WFlags flags = 0);
    
private:
    void sendToClient(QTcpSocket* pSocket, const QString& str);

private slots:
    void slotNewConnection();
    void slotReadClient();

};
#endif // SERVER_H


server.cpp
Код

#include "server.h"
#include <QtGui>
#include <QtNetwork>

Server::Server(int nPort, QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags), m_nNextBlockSize(0) // конструктор класса
{
    txt = new QTextEdit;
    txt->setReadOnly(true);

    QVBoxLayout* pvbxLayout = new QVBoxLayout;
    pvbxLayout->addWidget(new QLabel("<H1>Server</H1>"));
    pvbxLayout->addWidget(txt);
    setLayout(pvbxLayout);
    qDebug() << nPort;
    tcpServer = new QTcpServer(this);
    if (!tcpServer->listen(QHostAddress::LocalHost, nPort))
    {
        QMessageBox::critical(0, tr("Server Error"), tr("Unable to start Server: %1") .arg(tcpServer->errorString()));
        tcpServer->close();
        return;
    }
    connect(tcpServer, SIGNAL(newConnection()),
        this, SLOT(slotNewConnection())); // слот вызывается при каждом присоединении нового клиента
}

void Server::slotNewConnection()
{
    QTcpSocket* clientSocket = tcpServer->nextPendingConnection(); // для подтверждения соединения с клиентом
                                // возвращает сокет для связи с клиентом
    connect(clientSocket, SIGNAL(disconnected()),
        clientSocket, SLOT(deleteLater()));
    connect(clientSocket, SIGNAL(readyRead()),
        this, SLOT(slotReadClient())); // при поступлении запросов от клиентов
    sendToClient(clientSocket, "Server Response: Connected!"); // отправляем клиенту уведомление
}

void Server::slotReadClient()
{
    QTcpSocket* clientSocket = (QTcpSocket*)sender();
    QDataStream in(clientSocket);
    in.setVersion(QDataStream::Qt_4_5);
    for (;;)
    {
        if (!m_nNextBlockSize)
        {
            if (clientSocket->bytesAvailable() < sizeof(quint16))
                break;
            in >> m_nNextBlockSize;
        }
        if (clientSocket->bytesAvailable() < m_nNextBlockSize)
            break;
        QTime time;
        QString str;
        in >> time >> str;

        QString strMessage = time.toString()+" "+"Client has sent - "+str;
        txt->append(strMessage);

        m_nNextBlockSize=0;

        sendToClient(clientSocket, "Server Response: Received \"" + str + "\"");
    }
}

void Server::sendToClient(QTcpSocket* pSocket, const QString& str)
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly); // так как мы не знаем размер блока, а этот размер должен быть в самом начале блока, то делаем хак.
    out.setVersion(QDataStream::Qt_4_5);
    out << quint16(0) << QTime::currentTime() << str; // сначала записываем в первое поле 0, а потом, после того, как известен размер всего блока,

    out.device()->seek(0); // перемещаем указатель на начало блока
    out << quint16(arrBlock.size() - sizeof(quint16)); // и записываем туда размер

    pSocket->write(arrBlock); // пишем блок в сокет (почему пишем не out???)
}


Вот они прекрасно обмениваются сообщениями. Надо искать разницу...
PM MAIL   Вверх
niklep
Дата 28.4.2011, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Опаньки... сменил в коде везде Qt_4_5 на Qt_4_7 как на сервере, так и на клиенте, и заработало... Я как-то не задумывался над этим значением. Там всегда нужно держать текущую установленную версия Qt?
PM MAIL   Вверх
borisbn
Дата 28.4.2011, 15:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Цитата(niklep @  28.4.2011,  14:23 Найти цитируемый пост)
    
QDataStream in(tcpSocket);    
in.setVersion(QDataStream::Qt_4_5);


проблема могла быть в несоответствии упаковки данных QDataStream разных версий.

Цитата(niklep @  28.4.2011,  14:38 Найти цитируемый пост)
Там всегда нужно держать текущую установленную версия Qt?

вопрос в том, что при компиляции и клиента и сервера нужно использовать одну и ту же версию Qt или в том, что нужно ли устанавливать Qt на компьютер, где будет крутиться программа (сервис) ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
niklep
Дата 28.4.2011, 21:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Цитата

проблема могла быть в несоответствии упаковки данных QDataStream разных версий.

Ну, на сервере и клиенте у меня версии совпадали. Странно. Qt_4_5 тоже в свое время взял из учебника и не менял с тех пор.
Цитата

вопрос в том, что при компиляции и клиента и сервера нужно использовать одну и ту же версию Qt или в том, что нужно ли устанавливать Qt на компьютер, где будет крутиться программа (сервис) ? 

Я имел ввиду, что в данной опции Qt_4_x необходимо указывать именно ту версию, которая установлена на компьютере(?) Естественно, у меня не возникало мыслей о том, что в коде сервера и клиента использовать разные опции Qt_4_x.
Вообще, вопрос можно сформулировать так: что данная опция вообще делает?
Например
Код

in.setVersion(QDataStream::Qt_4_5);

означает, что будет использоваться реализация Qt_4_5 для данного класса? Qt что, хранит в себе и старые версии библиотек тоже? Вряд ли...
PM MAIL   Вверх
borisbn
Дата 28.4.2011, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Цитата(niklep @  28.4.2011,  21:08 Найти цитируемый пост)
Qt что, хранит в себе и старые версии библиотек тоже? Вряд ли...

Нет, она хранит не версии библиотеки, а версии алгоритма сериализации/десериализации данных в QDataStream.
Почитай про setVersion и про Versioning



--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.1057 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.