Chinaunix首页 | 论坛 | 博客
  • 博客访问: 535827
  • 博文数量: 71
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 159
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-13 12:37
个人简介

aaaaaaaaa

文章分类

全部博文(71)

文章存档

2013年(71)

我的朋友

分类: 嵌入式

2013-07-24 17:15:05

前言

Qt包含了各式各样的模组供使用者使用与开发应用程式,而在网路程式设计的部分,就是由QtNetwork module来提供了各式各样的类别供程式设计师撰写TCP/IP为基础的网路应用程式,让程式设计师使用上更简单、容易移植。

QtNetwork module所提供的函式库包括了基本的HTTP与FTP应用层通讯协定的QHttp和QFtp,经由网路来下载或上传档案更加简单快速。

除了上层通讯协定之外,也包含了底层网路类别,包括了QTcpSocket与QUdpSocket,这些类别分别实做了TCP与UDP这两个传输层通讯协定,而在底层之上则包括有QnetworkRequest、QNetworkReply以及QNetworkAccessmanager, 利用一般的通讯协定来进行网路功能的运作。

QtNetwork module目前是属于Full Framework Edition与Open Souce Versions的一部份,Qt各版本的不同请参考。

在本篇将会介绍如何在Qt利用上述通讯协定来撰写程式。


[  ] 设定编译程序

若要撰写使用Qt网路功能的应用程式,势必会使用到Qt的那些网路类别,则必须在build的时候设定将QtNetwork模组加入。

简单来讲,其实只需要在qmake –project之后产生的project档(xxx.pro)加入下列的指令即可;如此一来,在qmake编译时,看到这行指令就会正确地连结(link)到QtNetwork函式库:

QT += network

至于为何需要此步骤呢?

由于Qt预设只会载入QtCore与QtGui这两个基本的模组,因此要使用其他模组就一定要加入此行指令(往后若有使用到其他模组,则可依此类推)。而在程式中要使用到QtNetwork module的类别时,只需要用下列指令加入即可:

#include 


[  ] 第一支Qt网路程式

知道如何撰写Qt Network程式的首要步骤之后,接着就是要撰写一个简单的程式做练习;而我们的第一支Qt网路程式就是利用QHttp和QFtp写一个简单的HTTP和FTP client。

HTTP(Hypertext Transfer Protocol)是应用层(application-level)的网路通讯协定,可用于下载HTML与XML档案,亦可使用于高阶传输的通讯协定,包括其他类型的资料传输等。而FTP(File Transfer Protocol)则几乎专用于浏览远端目录以及传输档案。


[  ] Http Client

QHttp提供了基本HTTP的功能,包括get()和post(),并且提供了各种方法来送HTTP request,而要撰写一个简单的HTTP程式其实不难,基本上只需要先了解如何使用下列QHttp的函式即可。

1、首先是设定HTTP伺服器的hostName与port:

int QHttp:: setHost  (  const QString & hostName, quint16 port = 80  )

此函式的运作是非同步(实际上,所有QHttp的运作皆是如此),并且会由requestStarted( )和requestFinished( )回传一个单一的识别。


2、设定要下载的档案(get请求给setHost()中设定的hostName以及路径):

int QHttp:: get  (  const QString & path, QIODevice * to = 0  )

path必须是一个绝对路径(eg, /index.html)或绝对URI( 


3、结束连线,常用于关闭一个keep-alive的连线(刚提到的get( )所送出的请求皆会被QHttp设定为keep-alive 连线):

int QHttp:: close  ( )

基本上只要使用到上述的函式即可建立连线并且下载档案,就是一个很简易的Http客户端了,

皆下来范例程式,在命令列模式下利用HTTP get来下载指定的档案:

#include  #include  #include  #include  #include  using  namespace std; int main ( int argc, char * argv [ ] ) { QCoreApplication app ( argc, argv ) ; 	QFile * file ; 	QHttp *http = new QHttp ( ) ; 	QUrl url ( "" ) ; 	QFileInfo fileInfo ( url. path ( ) ) ; 	QString fileName = fileInfo. fileName ( ) ; file = new QFile ( fileName ) ; if ( !file->open ( QIODevice:: WriteOnly ) ) { cerr << "Unable to save the file" << endl; delete file ; file = 0 ; } http ->setHost ( url. host ( ) , url. port ( 80 ) ) ; 	http->get ( url. path ( ) , file ) ; 	http->close ( ) ; return app. exec ( ) ; }                                       

上述的范例是不是很浅显易懂呢?以下有几个部分特别说明一下:

  1. 由于未使用到UI介面,因此并不需要使用到QtGui函式库,所以使用QCoreApplication
  2. 如何在本机磁碟储存档案的部分,就不在此多做说明了
  3. 而主要利用Http下载档案的部分,就看最后面那几行程式即可,应该也是很清楚
  4. 而要指定下载的网路位址,我们用QUrl来指定


[  ] Ftp Client

QFtp提供FTP通讯协定的实做,包括interface让使用者直接使用来控制其中的request。这个类别的运作是非同步的,因此如果函式无法立即执行,则执行动作将会排程稍后再执行。而所有执行动作的结果都会经由signal回报,能够被排程的指令包括connectToHost()、 login()、close(),、list()、cd()、get()、put()、remove() 、mkdir()、rmdir()、 rename()和rawCommand()。

所有的指令都会回传一个单一的识别值(identifier),以方便追踪指令是否被执行。当某个指令开始执行时,会发送commandStarted() signal,并且伴随着那个指令的识别值(identifier);而当指令结束时,commandFinished() signal会发送并伴随着指令的识别值,并且还有一个bool值说明指令是否有发生错误。

以下撷取出连线到FTP伺服器的部分程式码:

QFtp *ftp = new QFtp (  ) ; 
ftp->connectToHost ( "ftp.isu.edu.tw/" ) ; 
ftp->login ( ) ;

以下是一个简单的范例程式,利用FTP通讯协定到指定的位址下载档案。范例档案与上力的HTTP类似,因此我将只列出实际执行下载档案的程式内容:

ftp->setTransferMode ( QFtp:: Passive ) ; 
ftp->connectToHost ( “ftp. isu . edu . tw) ; 
ftp->login ( ) ; 
ftp->cd ( "pub" ) ; 
ftp->get ( " 00_index.txt" ) ; 
ftp->close ( ) ;

上面的程式码片段是利用FTP连接至ftp.isu.edu.tw,并且是Passive Mode连线(预设)。

connectToHost( )中若未指定port,则为预设的21。

cd( )将进入指定的位置,而get( )则指定要下载的档案。

最后close()结束连线。


以下是一个简易的范例程式,而与前一个范例不同的是,这个范例将会使用到.h表头档,所以档案会比较多。


首先,请看FtpGet.h:

#ifndef FTPGET_H  #define FTPGET_H    #include     class QUrl; class QFtp; class QFile; class FtpGet : public QObject { Q_OBJECT public :     FtpGet ( QObject *parent = 0 ) ; void downloadFile ( const QUrl &url ) ; signals: void finished ( ) ; private slots: void done ( bool error ) ; private :     QFtp *ftp;     QFile * file ; } ; #endif                         

上述档案有几个需要注意的部分:

  1. 一开始的#ifndef FTPGET_H与#define FTPGET_H其实就是一般典型C++设定表头档常使用到的,主要是防止重复定义
  2. 而再来的几个class,主要是将会使用到这些类别,预先包含进来,再后面的实做档就不用在include进来,而可以在这里先使用
  3. 由于会自订SIGNAL/SLOT,所以需要Q_OBJECT
  4. 以下自订的函式与SIGNAL与SLOTk的部分就不多加赘述啰


再来请看实做类别的FtpGet.cpp:

#include   #include   #include     #include "FtpGet.h"  using  namespace std; FtpGet:: FtpGet ( QObject *parent )  : QObject ( parent ) { ftp = new QFtp ( this ) ;     connect ( ftp, SIGNAL ( done ( bool ) ) , this , SLOT ( done ( bool ) ) ) ; } void FtpGet:: downloadFile ( const QUrl &url ) { QFileInfo fileInfo ( url. path ( ) ) ;     QString fileName = fileInfo. fileName ( ) ; file = new QFile ( fileName ) ; if ( !file->open ( QIODevice:: WriteOnly ) ) { cerr << "Unable to save the file" << endl; delete file ; file = 0 ; return ; } ftp->setTransferMode ( QFtp:: Passive ) ;     ftp->connectToHost ( url. host ( ) , url. port ( 21 ) ) ;     ftp->login ( ) ;     ftp->get ( url. path ( ) , file ) ;					             ftp->close ( ) ; } void FtpGet:: done ( bool error ) { if ( error ) { cerr << "Error: " << qPrintable ( ftp->errorString ( ) ) << endl; } else { cerr << "File downloaded as " << qPrintable ( file->fileName ( ) ) << endl; } file->close ( ) ; delete file ; file = 0 ;     emit finished ( ) ; }                                                      

上述档案有几个需要注意的部分:

  1. 在constructor的部分,先实体化一个ftp物件,并且做了SIGNAL/SLOT connection
  2. downloadFile就是利用FTP下载档案的主要部分,就不多加说明啰
  3. 再来就是自订的SIGNAL部分,请自行研究


最后就是main.cpp的部分:

#include   #include   #include "FtpGet.h"  #include   using  namespace std; int main ( int argc, char *argv [ ] ) { QCoreApplication app ( argc, argv ) ;     FtpGet getter;     getter. downloadFile ( QUrl ( "ftp://ftp.isu.edu.tw/00_index.txt" ) ) ;     QObject:: connect ( &getter, SIGNAL ( finished ( ) ) , &app, SLOT ( quit ( ) ) ) ; return app. exec ( ) ; }               

这部分就很简单啰,请自行看吧。 

原文链接:








阅读(1098) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~