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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Простой браузер без Web-kit.  (Прочитано 4631 раз)
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_

Оффтоп: а убрать код в спойлер тут нельзя никак?
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #1 : Апрель 09, 2011, 17:14 »

Цитировать
Стоит добавить в класс с сокетом тег Q_OBJECT как прога отказывается компилиться из-за вызова функции connect. Которую компилятор воспринимает как метод QObject::connect() ибо сокет лежит в классе QThread который вроде как от QObject унаследован.
В чем проблема принудительно указать компилятору от какого класса метод connect мы вызываем?
Что значит сокет лежит в QThread?
Записан
Silver_swift
Гость
« Ответ #2 : Апрель 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));
...
}

};
« Последнее редактирование: Апрель 09, 2011, 17:40 от Silver_swift » Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #3 : Апрель 09, 2011, 18:45 »

проблема понятна используй оператор разрешения области видимости. Т.е. пиши

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

};
Записан
merke
Гость
« Ответ #4 : Апрель 10, 2011, 06:40 »

Нафига тебе сокеты, используй QNetworkAccessManager.
Записан
Silver_swift
Гость
« Ответ #5 : Апрель 11, 2011, 00:08 »

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

Сообщений: 846


Просмотр профиля
« Ответ #6 : Апрель 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));
}
};
/////////////////////////////////////////////////////////////////
Записан
Silver_swift
Гость
« Ответ #7 : Апрель 11, 2011, 01:29 »

Я что-то совсем перестал понимать что происходит.
Открываю пример с созданием потока из книги Шлее. В той папке где он лежал он компилится и работает. Файлов всего 2 .pro и .cpp. копирую их в свой проект и при компиляции получаю ошибки о которых писал выше.
Оба проекта одного типа, код в них одинаковый.
Как такое может быть???
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #8 : Апрель 11, 2011, 02:10 »

Очень просто - пути к либам неправильно прописанфы в твоем проекте, или не прописаны, или неверные модули Qt указаны так что линкер не находит нужных ему библиотек - вот и ругается. Сравнивай pro файлы - возможно указаны относительные пути а один из проектов на уровень выше находится в реальной ФС или что-то подобное.
Записан
Silver_swift
Гость
« Ответ #9 : Апрель 11, 2011, 15:03 »

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

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

Edited: Для progress-bar откуда можно получить информацию о загрузке страницы? Учитывая что у меня сокет не класс Qt...
« Последнее редактирование: Апрель 11, 2011, 15:07 от Silver_swift » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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