Russian Qt Forum

Qt => Работа с сетью => Тема начата: Silver_swift от Апрель 09, 2011, 17:01



Название: Простой браузер без Web-kit.
Отправлено: Silver_swift от Апрель 09, 2011, 17:01
Всем привет. Учусь в инсте по заданию нужно сделать браузер который отсылает http запрос на сервак и отображает полученный гипертекст.

1. С использованием TCP-сокетов для линуха (sys/socket.h) в консоли "браузер" работает без проблем.
Подружить его с интерфейсом не получилось. Стоит добавить в класс с сокетом тег Q_OBJECT как прога отказывается компилиться из-за вызова функции connect. Которую компилятор воспринимает как метод QObject::connect() ибо сокет лежит в классе QThread который вроде как от QObject унаследован.

2. Плюнул на это дело, пробую использовать QTcpSocket. Мой код ничего не принимал, тогда взял пример из книги Шлее (глава 40 про TCP сервер и клиент) переписал под свои нужды клиента.
Запускаю клиента и сервера на порте 8011. На сервер запрос приходит правильно.
Пробую подключить клиента к порту 80:
Цитировать
Received the connected() signal
Error: The remote host is closed.

И теперь вопросы:
1. Почему такая ошибка возникает?
2. Просто интересно в отдельном потоке (QThread) функцию connect для TCP-сокета из sys/socket.h можно как-то вызвать? Ведь есть и другие функции С++ названия которых совпадают с методами классов Qt.

Код клиента:
main.cpp
Код:
/* ======================================================================
**  main.cpp
** ======================================================================
**
** ======================================================================
**  Copyright (c) 2007 by Max Schlee
** ======================================================================
*/

#include <QApplication>
#include "MyClient.h"

// ----------------------------------------------------------------------
int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    MyClient     client("127.0.0.1",(quint16) 80);

    client.show();

    return app.exec();
}


MyClient.cpp
Код:
#include <QtNetwork>
#include <QtGui>
#include "MyClient.h"

MyClient::MyClient(const QString& strHost,
                   int            nPort,
                   QWidget*       pwgt
                  ) : QWidget(pwgt)
                    , m_nNextBlockSize(0)
{
    m_pTcpSocket = new QTcpSocket(this);
    m_pTcpSocket->connectToHost(strHost, nPort);
    connect(m_pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
    connect(m_pTcpSocket, SIGNAL(readyRead()), SLOT(slotReadyRead()));
    connect(m_pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this,         SLOT(slotError(QAbstractSocket::SocketError))
           );

    m_ptxtInfo  = new QTextEdit;
    m_ptxtInfo->setReadOnly(true);

    QPushButton* pcmd = new QPushButton("&Send");
    connect(pcmd, SIGNAL(clicked()), SLOT(slotSendToServer()));


    QVBoxLayout* pvbxLayout = new QVBoxLayout;
    pvbxLayout->addWidget(new QLabel("<H1>Client</H1>"));
    pvbxLayout->addWidget(m_ptxtInfo);
    pvbxLayout->addWidget(pcmd);
    setLayout(pvbxLayout);
}


void MyClient::slotReadyRead()
{
    QDataStream in(m_pTcpSocket);
    in.setVersion(QDataStream::Qt_4_2);
    for (;;) {
        if (!m_nNextBlockSize) {
            if (m_pTcpSocket->bytesAvailable() < sizeof(quint16)) {
                break;
            }
            in >> m_nNextBlockSize;
        }

        if (m_pTcpSocket->bytesAvailable() < m_nNextBlockSize) {
            break;
        }

        QString str;
        in >> str;

        m_ptxtInfo->append(str);
        m_nNextBlockSize = 0;
    }
}

void MyClient::slotError(QAbstractSocket::SocketError err)
{
    QString strError =
        "Error: " + (err == QAbstractSocket::HostNotFoundError ?
                     "The host was not found." :
                     err == QAbstractSocket::RemoteHostClosedError ?
                     "The remote host is closed." :
                     err == QAbstractSocket::ConnectionRefusedError ?
                     "The connection was refused." :
                     QString(m_pTcpSocket->errorString())
                    );
    m_ptxtInfo->append(strError);
}

void MyClient::slotSendToServer()
{

    QByteArray  arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_2);
    QString ss("GET /\r\nHost:127.0.0.1");
    out << quint16(0) << ss;

    out.device()->seek(0);
    out << quint16(arrBlock.size() - sizeof(quint16));

    m_pTcpSocket->write(arrBlock);

}

// ------------------------------------------------------------------
void MyClient::slotConnected()
{
    m_ptxtInfo->append("Received the connected() signal");
}

MyClient.h
Код:
#ifndef _MyClient_h_
#define _MyClient_h_

#include <QWidget>
#include <QTcpSocket>

class QTextEdit;
class QLineEdit;

class MyClient : public QWidget {
Q_OBJECT
private:
    QTcpSocket* m_pTcpSocket;
    QTextEdit*  m_ptxtInfo;

    quint16     m_nNextBlockSize;

public:
    MyClient(const QString& strHost, int nPort, QWidget* pwgt = 0) ;

private slots:
    void slotReadyRead   (                            );
    void slotError       (QAbstractSocket::SocketError);
    void slotSendToServer(                            );
    void slotConnected   (                            );
};
#endif  //_MyClient_h_

Оффтоп: а убрать код в спойлер тут нельзя никак?


Название: Re: Простой браузер без Web-kit.
Отправлено: break от Апрель 09, 2011, 17:14
Цитировать
Стоит добавить в класс с сокетом тег Q_OBJECT как прога отказывается компилиться из-за вызова функции connect. Которую компилятор воспринимает как метод QObject::connect() ибо сокет лежит в классе QThread который вроде как от QObject унаследован.
В чем проблема принудительно указать компилятору от какого класса метод connect мы вызываем?
Что значит сокет лежит в QThread?


Название: Re: Простой браузер без Web-kit.
Отправлено: Silver_swift от Апрель 09, 2011, 17:30
Цитировать
В чем проблема принудительно указать компилятору от какого класса метод connect мы вызываем?
В том что эта функция вроде как не принадлежит ни какому классу. Я бы даже посмотрел в самой библиотеке. Только не знаю где она лежит в убунте  ???
Edited:
Нашел прототип в библиотеке:
extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
Функция действительно не принадлежит никакому классу.
Цитировать
Что значит сокет лежит в QThread?
Код:
#include <sys/socket.h>
....
class stream : public QThread
{
Q_OBJECT
void run ()
{
...
connect(sockfd,(struct sinaddr*)ADR, sizeof(*ADR));
...
}

};


Название: Re: Простой браузер без Web-kit.
Отправлено: break от Апрель 09, 2011, 18:45
проблема понятна используй оператор разрешения области видимости. Т.е. пиши

#include <sys/socket.h>
....
class stream : public QThread
{
Q_OBJECT
void run ()
{
...
::connect(sockfd,(struct sinaddr*)ADR, sizeof(*ADR));
...
}

};


Название: Re: Простой браузер без Web-kit.
Отправлено: merke от Апрель 10, 2011, 06:40
Нафига тебе сокеты, используй QNetworkAccessManager.


Название: Re: Простой браузер без Web-kit.
Отправлено: Silver_swift от Апрель 11, 2011, 00:08
To break: так сначала и пробовал. Но как только в классе потока появится тег Q_OBJECT компилятор два раза выводит строку "undefined reference to 'vtable for sock' " ( класс моего потока с сокетом) и "collect2: ld returned 1 exit status".
К сожалению код пока не могу выложить - сижу с телефона.
Зря я думал, что косяк в методе connect(). Видимо проблема в создании потока с этим тегом.
Есть какие-нибудь соображения?


Название: Re: Простой браузер без Web-kit.
Отправлено: break от Апрель 11, 2011, 00:36
Разбирайся с линкером - у меня вот так все компилится

Код:
/////////////////////////////////////////////////////////////////
#include <sys/socket.h>
#include <QThread>
class stream : public QThread
{
Q_OBJECT
void run ()
{
int sockfd;
const sockaddr * ADR;
::connect(sockfd,(struct sockaddr*)ADR, sizeof(*ADR));
}
};
/////////////////////////////////////////////////////////////////


Название: Re: Простой браузер без Web-kit.
Отправлено: Silver_swift от Апрель 11, 2011, 01:29
Я что-то совсем перестал понимать что происходит.
Открываю пример с созданием потока из книги Шлее. В той папке где он лежал он компилится и работает. Файлов всего 2 .pro и .cpp. копирую их в свой проект и при компиляции получаю ошибки о которых писал выше.
Оба проекта одного типа, код в них одинаковый.
Как такое может быть???


Название: Re: Простой браузер без Web-kit.
Отправлено: break от Апрель 11, 2011, 02:10
Очень просто - пути к либам неправильно прописанфы в твоем проекте, или не прописаны, или неверные модули Qt указаны так что линкер не находит нужных ему библиотек - вот и ругается. Сравнивай pro файлы - возможно указаны относительные пути а один из проектов на уровень выше находится в реальной ФС или что-то подобное.


Название: Re: Простой браузер без Web-kit.
Отправлено: Silver_swift от Апрель 11, 2011, 15:03
Спасибо, понял в чем был косяк. Не тот проект был указан в TARGET и теперь даже все заработало.
Вот так вот бывает - думаешь что косяк в сокете, мучаешься с ним, а потом оказывается что дело совсем не в нем)))

А все же, если использовать QTcpSocket почему ошибка возникает?

Edited: Для progress-bar откуда можно получить информацию о загрузке страницы? Учитывая что у меня сокет не класс Qt...