diff --git a/README.md b/README.md index 7d93f9c9..f14a2e00 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ github link: https://github.com/AbelTian/LibQQt - QQtSerialPort 兼容QSerialPort and QextSerialPort - [QQtTcpClient](src/network/qqttcpclient.h)、QQtTcpServer、QQtUdpClient、QQtUdpServer - QQtBluetoothSocket、QQtBluetoothServer +QQtBluetoothManager - - QQtWebAccessManager,支持http、ftp等主流协议,高并发传输,管理cookie和session。 + - [QQtWebAccessManager](src/network/qqtwebaccessmanager.h)、[QQtWebLoader](src/network/qqtwebloader.h),支持http、ftp等主流协议,高并发传输,管理cookie和session。 - [QQtWebSocket](src/network/qqtwebsocketclient.h) 接口 - 一个句柄代表一个和外部通信的节点。 - 报文虚类(接口类) [QQtMessage](src/network/qqtmessage.h) diff --git a/src/highgrade/qqtdatapersistence.cpp b/src/highgrade/qqtdatapersistence.cpp deleted file mode 100644 index cad99372..00000000 --- a/src/highgrade/qqtdatapersistence.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include - -#include - -QQtDataPersistence::QQtDataPersistence ( QObject* parent ) - : QObject ( parent ) -{ - reset_marker(); - mDataFormat = JsonData; - - mTimerInterval = 1000; - mTimer = new QTimer ( this ); - mTimer->setSingleShot ( false ); - mTimer->setInterval ( mTimerInterval ); - connect ( mTimer, SIGNAL ( timeout() ), - this, SLOT ( slotTimeOut() ) ); -} - -QQtDataPersistence::~QQtDataPersistence() {} - -void QQtDataPersistence::setDataFormat ( QQtDataPersistence::DataFormat format ) { mDataFormat = format; } - -QQtDataPersistence::DataFormat QQtDataPersistence::dataFormat() const { return mDataFormat; } - -void QQtDataPersistence::setDataFile ( const QString& fileName ) -{ - mFileName = fileName; - if ( mFileName.isEmpty() ) - return; - parseContentToDictionary(); -} - -QString QQtDataPersistence::dataFile() const { return mFileName; } - -void QQtDataPersistence::prepareDataPersistence() -{ - if ( mFileName.isEmpty() ) - return; - mTimer->start(); -} - -void QQtDataPersistence::exitDataPersistence() -{ - mTimer->stop(); -} - -void QQtDataPersistence::start() -{ - mLock.lockForWrite(); -} - -QQtDictionary& QQtDataPersistence::dictionary() -{ - return mDict; -} - -const QQtDictionary& QQtDataPersistence::dictionary() const -{ - return mDict; -} - -void QQtDataPersistence::stop() -{ - marker(); - mLock.unlock(); -} - -int QQtDataPersistence::timerInterval() const { return mTimerInterval; } - -void QQtDataPersistence::setTimerInterval ( int millSecond ) { mTimerInterval = millSecond; } - -void QQtDataPersistence::slotTimeOut() -{ - /*减少写文件;marker强制写*/ - if ( getMarker() == false ) - { - return; - } - //用户设置了marker标记true,强制写 - setMarker ( false ); - - QByteArray bytes; - packDictionaryToContent ( bytes ); - writeFile ( bytes ); -} - -void QQtDataPersistence::parseContentToDictionary() -{ - QByteArray bytes; - readFile ( bytes ); - - mLock.lockForWrite(); - mDict.clear(); - switch ( mDataFormat ) - { - case JsonData: - mDict.fromJson ( bytes ); - break; - case XmlData: - mDict.fromXML ( bytes ); - break; -#ifdef __YAMLSUPPORT__ - case YamlData: - mDict.fromYAML ( bytes ); - break; -#endif -#ifdef __INICONTENTSUPPORT__ - case IniData: - mDict.fromINI ( bytes ); - break; - case PropertiesData: - mDict.fromProperties ( bytes ); - break; -#endif -#ifdef __QTCSVLIB__ - case CSVData: - mDict.fromCSV ( bytes ); - break; -#endif - case MaxFormat: - default: - break; - } - mLock.unlock();; -} - -void QQtDataPersistence::packDictionaryToContent ( QByteArray& bytes ) -{ - mLock.lockForRead(); - switch ( mDataFormat ) - { - case JsonData: - bytes = mDict.toJson ( QJsonDocument::Indented ); - break; - case XmlData: - bytes = mDict.toXML ( 4 ); - break; -#ifdef __YAMLSUPPORT__ - case YamlData: - bytes = mDict.toYAML ( ); - break; -#endif -#ifdef __INICONTENTSUPPORT__ - case IniData: - bytes = mDict.toINI ( ); - break; - case PropertiesData: - bytes = mDict.toProperties ( ); - break; -#endif -#ifdef __QTCSVLIB__ - case CSVData: - bytes = mDict.toCSV ( ); - break; -#endif - case MaxFormat: - default: - break; - } - mLock.unlock();; -} - -void QQtDataPersistence::readFile ( QByteArray& bytes ) -{ - if ( mFileName.isEmpty() ) - return; - - QFile file ( mFileName ); - //pline() << "file:" << mFileName << file.exists(); - if ( file.exists() ) - file.open ( QFile::ReadOnly ); - else - file.open ( QFile::Truncate | QFile::ReadWrite ); - bytes = file.readAll(); - file.close(); -} - -void QQtDataPersistence::writeFile ( const QByteArray& bytes ) -{ - if ( mFileName.isEmpty() ) - return; - - QFile file ( mFileName ); - if ( file.exists() ) - file.open ( QFile::WriteOnly ); - else - file.open ( QFile::Truncate | QFile::WriteOnly ); - file.write ( bytes ); - file.close(); -} - -void QQtDataPersistence::marker () -{ - bMarker = true; -} - -void QQtDataPersistence::reset_marker() -{ - bMarker = false; -} - -void QQtDataPersistence::setMarker ( bool mark ) -{ - bMarker = mark; -} - -bool QQtDataPersistence::getMarker() const -{ - return bMarker; -} diff --git a/src/highgrade/qqtdatapersistence.h b/src/highgrade/qqtdatapersistence.h deleted file mode 100644 index 1020c944..00000000 --- a/src/highgrade/qqtdatapersistence.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef QQTDATAPERSISTENCE_H -#define QQTDATAPERSISTENCE_H - -#include -#include -#include - -#include - -#include - -/** - * @brief The QQtDataPersistence class - * 数据持久化类 - * - * 支持: - * 设置持久化保存间隔 - * 支持设置保存格式 - * 支持开启、关闭持久化功能,关闭后就是个普通的字典类 - * - * 原理: - * 初始化数据格式、数据文件 - * 开启数据持久化功能,同时 根据数据格式读取数据文件初始化内部字典。 - * 有一个Timer,持续加锁读取内部字典,根据数据格式,保存到数据文件。 - * 用户可以持续加锁,读取、写入内部的字典。 - * - * 注意事项: - * 如果数据文件不存在,将会自动创建文件, - * 这个类对持久化存储数据文件的访问是非独占式, - * 1. 用户私自写同一个数据文件,本句柄不会自动覆盖; - * 2. 两个数据持久化类句柄共同写同一个数据文件,不会竞争,修改时写、Mark时写,最后一次写文件者决定文件内容。 - * - * 使用方法: - * QQtDataPersistence keep_inst; - * keep_inst.PrepareDataPersistence(); //打开持久化功能。once。 - * - * keep_inst.start(); //开始持久化数据操作 每次操作都需要开启和关闭 - * QQtDictionary& handler = keep_inst.dictionary(); //可以操作的数据句柄 - * handler.clear(); //可选:字典数据从新开始。 - * handler["key1"]["key2"] = "value1"; //字典发生改变,内部自动保存 - * ... - * keep_inst.marker(); // 强制保存! - * keep_inst.stop(); //停止持久化数据操作 - * - * keep_inst.ExitDataPersistence(); //退出持久化功能。普通buffer,不再保存数据。 - */ -class QQTSHARED_EXPORT QQtDataPersistence : public QObject -{ - Q_OBJECT - -public: - explicit QQtDataPersistence ( QObject* parent = 0 ); - virtual ~QQtDataPersistence(); - - enum DataFormat - { - JsonData, - XmlData, - YamlData, - IniData, - PropertiesData, - CSVData, - - MaxFormat - }; - //数据格式 - void setDataFormat ( DataFormat format = JsonData ); - DataFormat dataFormat() const; - - //持久化数据文件 [+初始化字典] - void setDataFile ( const QString& fileName ); - QString dataFile() const; - - //打开数据持久化 - void prepareDataPersistence(); - //关闭数据持久化 - void exitDataPersistence(); - - //1! 开启 - void start(); - - //2! 操作 - QQtDictionary& dictionary(); - const QQtDictionary& dictionary() const; - - //3! 关闭 - void stop(); - - //持久化数据保存周期 [default:1000ms] - int timerInterval() const; - void setTimerInterval ( int millSecond = 1000 ); - -private slots: - void slotTimeOut(); - -protected: - virtual void parseContentToDictionary(); - virtual void packDictionaryToContent ( QByteArray& bytes ); - - //方便函数。文件不存在会创建。 - virtual void readFile ( QByteArray& bytes ); - virtual void writeFile ( const QByteArray& bytes ); - -private: - - /*设置标记*/ - void marker (); - /*重置标记*/ - void reset_marker (); - /*设置标记 default: true*/ - void setMarker ( bool mark = true ); - /*获取标记 default: false*/ - bool getMarker() const; - - /*一个标记*/ - bool bMarker; - -private: - QReadWriteLock mLock; - QQtDictionary mDict; - - QTimer* mTimer; - int mTimerInterval; - DataFormat mDataFormat; - QString mFileName; -}; - -#endif // QQTDATAPERSISTENCE_H - diff --git a/src/network/qqtwebloader.cpp b/src/network/qqtwebloader.cpp new file mode 100644 index 00000000..4895f142 --- /dev/null +++ b/src/network/qqtwebloader.cpp @@ -0,0 +1,174 @@ +#include + +QQtNetworkReply::QQtNetworkReply ( QObject* parent ) : QNetworkReply ( parent ) +{ + open ( QIODevice::ReadWrite ); +} + +QQtNetworkReply::~QQtNetworkReply() +{ + close(); +} + +QQtNetworkReply::QQtNetworkReply ( const QQtNetworkReply& other ) +{ + *this = ( const QNetworkReply& ) other; +} + +QQtNetworkReply& QQtNetworkReply::operator = ( const QNetworkReply& other ) +{ + setOperation ( other.operation() ); + setRequest ( other.request() ); + setError ( other.error(), other.errorString() ); + setFinished ( other.isFinished() ); + setUrl ( other.url() ); + + for ( int i = ( int ) QNetworkRequest::ContentTypeHeader; + i <= ( int ) QNetworkRequest::ServerHeader; i++ ) + { + QNetworkRequest::KnownHeaders ii = ( QNetworkRequest::KnownHeaders ) i; + setHeader ( ii, other.header ( ii ) ); + } + + QListIterator itor ( other.rawHeaderList() ); + while ( itor.hasNext() ) + { + const QByteArray& key = itor.next(); + setRawHeader ( key, other.rawHeader ( key ) ); + } + + for ( int i = ( int ) QNetworkRequest::HttpStatusCodeAttribute; + i <= ( int ) QNetworkRequest::RedirectPolicyAttribute; i++ ) + { + QNetworkRequest::Attribute ii = ( QNetworkRequest::Attribute ) i; + setAttribute ( ii, other.attribute ( ii ) ); + } + setAttribute ( QNetworkRequest::User, other.attribute ( QNetworkRequest::User ) ); + +#ifndef QT_NO_SSL + setSslConfiguration ( other.sslConfiguration() ); +#endif + return *this; +} + +qint64 QQtNetworkReply::readData ( char* data, qint64 maxlen ) +{ + int size1 = mBytes.size(); + if ( maxlen < size1 ) + size1 = maxlen; + memcpy ( data, mBytes.constData(), size1 ); + mBytes.remove ( 0, size1 ); + return size1; +} + +qint64 QQtNetworkReply::writeData ( const char* data, qint64 len ) +{ + mBytes.push_back ( QByteArray ( data, len ) ); + return len; +} + +void QQtNetworkReply::abort() +{ + // +} + + +QQtWebLoader::QQtWebLoader ( QObject* parent ) + : QObject ( parent ) +{ + mWebAccessManager = new QQtWebAccessManager ( this ); + + connect ( mWebAccessManager, SIGNAL ( replyFinished ( QQtWebAccessSession* ) ), + this, SLOT ( localReplyFinished ( QQtWebAccessSession* ) ) ); + connect ( mWebAccessManager, SIGNAL ( replyTimeOut ( QQtWebAccessSession* ) ), + this, SLOT ( localReplyTimeout ( QQtWebAccessSession* ) ) ); + + setTimerInterval(); +} + +QQtWebLoader::~QQtWebLoader() {} + +void QQtWebLoader::setTimerInterval ( int millsecond ) +{ + mWebAccessManager->setTimerInterval ( millsecond ); +} + +int QQtWebLoader::timerInterval() +{ + return mWebAccessManager->timerInterval(); +} + +QQtWebAccessSession* QQtWebLoader::get ( const QString& url ) +{ + QNetworkRequest netRequest; + netRequest.setUrl ( QUrl ( url ) ); //地址信息 + return get ( netRequest ); +} + +QQtWebAccessSession* QQtWebLoader::get ( const QNetworkRequest& req ) +{ + QQtWebAccessSession* session = mWebAccessManager->sendGetRequest ( req ); + + int millsecond = timerInterval(); + //manager的时钟设置会直接影响到session。 + //如果用户希望更改某个确定的session的超时,可以按照这个思路更改。 + //session->getTimer()->setInterval ( millsecond ); + //session->getTimer()->start(); + millsecond += 1000; + //+1s 给内部超时提供一定的缓冲时间,其实就是处理完超时,本地的timeout函数解锁。 + + block1.lock ( millsecond ); + + return &session1; +} + +QQtWebAccessSession* QQtWebLoader::post ( const QString& url, const QByteArray& data ) +{ + QNetworkRequest netRequest; + netRequest.setUrl ( QUrl ( url ) ); //地址信息 + return post ( netRequest, data ); +} + +QQtWebAccessSession* QQtWebLoader::post ( const QNetworkRequest& req, const QByteArray& data ) +{ + QQtWebAccessSession* session = mWebAccessManager->sendPostRequest ( req, data ); + + int millsecond = timerInterval(); + //manager的时钟设置会直接影响到session。 + //如果用户希望更改某个确定的session的超时,可以按照这个思路更改。 + //session->getTimer()->setInterval ( millsecond ); + //session->getTimer()->start(); + millsecond += 1000; + //+1s 给内部超时提供一定的缓冲时间,其实就是处理完超时,本地的timeout函数解锁。 + + block1.lock ( millsecond ); + return &session1; +} + +void QQtWebLoader::localReplyFinished ( QQtWebAccessSession* session ) +{ + //把session信息保存到本地,才能保留下来。 + reply1 = * ( session->getWebAccessReply() ); + reply1.write ( session->getWebAccessReply()->readAll() ); + + session1.setWebAccessSessionName ( session->getWebAccessSessionName() ); + session1.setWebAccessUrl ( session->getWebAccessUrl() ); + session1.getTimer()->setInterval ( session->getTimer()->interval() ); + session1.setWebAccessReply ( &reply1 ); + session1.webAccessRequest() = session->webAccessRequest(); + + block1.unlock(); +} + +void QQtWebLoader::localReplyTimeout ( QQtWebAccessSession* session ) +{ + reply1 = * ( session->getWebAccessReply() ); + //reply1.write ( session->getWebAccessReply()->readAll() );//??? + + session1.setWebAccessSessionName ( session->getWebAccessSessionName() ); + session1.setWebAccessUrl ( session->getWebAccessUrl() ); + session1.getTimer()->setInterval ( session->getTimer()->interval() ); + session1.setWebAccessReply ( &reply1 ); + session1.webAccessRequest() = session->webAccessRequest(); + block1.unlock(); +} diff --git a/src/network/qqtwebloader.h b/src/network/qqtwebloader.h new file mode 100644 index 00000000..57e82e2a --- /dev/null +++ b/src/network/qqtwebloader.h @@ -0,0 +1,88 @@ +#ifndef QQTWEBLOADER_H +#define QQTWEBLOADER_H + +#include + +#include +#include + +class QQTSHARED_EXPORT QQtNetworkReply : public QNetworkReply +{ + Q_OBJECT +public: + explicit QQtNetworkReply ( QObject* parent = 0 ); + virtual ~QQtNetworkReply(); + + QQtNetworkReply ( const QQtNetworkReply& other ); + QQtNetworkReply& operator = ( const QNetworkReply& other ); + + // QIODevice interface +protected: + virtual qint64 readData ( char* data, qint64 maxlen ) override; + + // QIODevice interface +protected: + virtual qint64 writeData ( const char* data, qint64 len ) override; + + // QNetworkReply interface +public slots: + virtual void abort() override; + +private: + QByteArray mBytes; +}; + +/** + * @brief The QQtWebLoader class + * 当前线程内使用,不会阻塞GUI。 + * + * Http请求工具,阻塞版。不可重入,不可跨线程。 + * 支持get、支持post + * + * 简单的HTTP请求。 + */ +class QQTSHARED_EXPORT QQtWebLoader : public QObject +{ + Q_OBJECT + +public: + explicit QQtWebLoader ( QObject* parent = 0 ); + virtual ~QQtWebLoader(); + + QQtWebAccessManager* manager() { + return mWebAccessManager; + } + + //返回的session里面的reply是QQtNetworkReply。 + //get之后,可以修改这一个session的超时?不可以。 + QQtWebAccessSession* get ( const QString& url ); + + //manager提供接口修改request,用户可以在session里修改?不可以。 + //这个接口提供给用户,manager没修改request的部分,用户可以改。 + QQtWebAccessSession* get ( const QNetworkRequest& req ); + + QQtWebAccessSession* post ( const QString& url, const QByteArray& data ); + QQtWebAccessSession* post ( const QNetworkRequest& req, const QByteArray& data ); + + //全局session有效 + void setTimerInterval ( int millsecond = 5000 ); + int timerInterval(); + + /* + * 以下和用户无关。 + */ +protected slots: + void localReplyFinished ( QQtWebAccessSession* session ); + void localReplyTimeout ( QQtWebAccessSession* session ); + +protected: + +private: + QQtWebAccessManager* mWebAccessManager; + QQtWebAccessSession session1; + QQtNetworkReply reply1; + QQtBlock block1; +}; + +#endif // QQTWEBLOADER_H + diff --git a/src/qqt_source.pri b/src/qqt_source.pri index 0492ad62..03576ac0 100644 --- a/src/qqt_source.pri +++ b/src/qqt_source.pri @@ -367,6 +367,9 @@ contains (DEFINES, __NETWORKSUPPORT__) { contains (DEFINES, __WEBACCESSSUPPORT__) { SOURCES += $$PWD/network/qqtwebaccessmanager.cpp HEADERS += $$PWD/network/qqtwebaccessmanager.h + + SOURCES += $$PWD/network/qqtwebloader.cpp + HEADERS += $$PWD/network/qqtwebloader.h } } @@ -690,11 +693,6 @@ contains (DEFINES, __HIGHGRADE__) { HEADERS += \ $$PWD/highgrade/qqtsingletonapplication.h } - - SOURCES += \ - $$PWD/highgrade/qqtdatapersistence.cpp - HEADERS += \ - $$PWD/highgrade/qqtdatapersistence.h } include ($$PWD/qqt_3rdparty.pri)