四十三、Qt网络(三)FTP(一)

news/2024/5/19 0:34:23 标签: qt, 网络, 服务器, ftp服务器, login, signal

 http://www.yafeilinux.com/?p=755#more-755

 

本文章原创于 www.yafeilinux.com 转载请注明出处。

上一节我们讲述了HTTP的编程,这一节讲述与其及其相似的FTP的编程。FTP即File Transfer Protocol,也就是文件传输协议。FTP的主要作用,就是让用户连接上一个远程计算机,查看远程计算机有哪些文件,然后把文件从远程计算机上拷贝到本地计算机,或者把本地计算机的文件送到远程计算机上。

     在Qt中,我们可以使用上一节讲述的QNetworkAccessManager和QNetworkReply类来进行FTP 程序的编写,因为它们用起来很简单。但是,对于较复杂的FTP操作,Qt还提供了QFtp类,利用这个类,我们很容易写出一个FTP客户端程序。下面我们先在帮助中查看这个类。

 Hosted by ImageHost.org

在QFtp中,所有的操作都对应一个特定的函数,我们可以称它们为命令。如connectToHost()连接到服务器命令,login()登录命令,get()下载命令,mkdir()新建目录命令等。因为QFtp类以异步方式工作,所以所有的这些函数都不是阻塞函数。也就是说,如果一个操作不能立即执行,那么这个函数就会直接返回,直到程序控制权返回Qt事件循环后才真正执行,它们不会影响界面的显示。

所有的命令都返回一个int 型的编号,使用这个编号让我们可以跟踪这个命令,查看其执行状态。当每条命令开始执行时,都会发出commandStarted()信号,当该命令执行结束时,会发出commandFinished()信号。我们可以利用这两个信号和命令的编号来获取命令的执行状态。当然,我们不想执行每条命令都要记下它的编号,所以我们也可以使用currentCommand()来获取现在执行的命令,其返回值与命令的对应关系如下图。

 Hosted by ImageHost.org

下面我们先看一个简单的FTP客户端的例子,然后对它进行扩展。

在这个例子中我们从FTP服务器上下载一个文件并显示出来。

1.我们新建Qt4 Gui QApplication 。

工程名为“myFtp”,然后选中QtNetwork模块,最后Base class选择QWidget 。

2.修改widget.ui文件。

在其中添加一个Text Browser 和一个 Label,效果如下。

 Hosted by ImageHost.org

3.在main.cpp中进行修改。

为了在程序中可以使用中文,我们在main.cpp中添加头文件#include <QTextCodec>

并在main()函数中添加代码:QTextCodec::setCodecForTr(QTextCodec::codecForLocale());

4.在widget.h中进行修改。

先添加头文件:#include <QFtp>

再在private中定义对象:QFtp *ftp;

添加私有槽函数:

private slots:

    void ftpCommandStarted(int);

void ftpCommandFinished(int,bool);

5.在widget.cpp中进行更改。

(1)在构造函数中添加代码:

ftp = new QFtp(this);

    ftp->connectToHost(“ftp.qt.nokia.com”); //连接到服务器

    ftp->login();   //登录

    ftp->cd(“qt”);   //跳转到“qt”目录下

    ftp->get(“INSTALL”);  //下载“INSTALL”文件

    ftp->close();   //关闭连接

    connect(ftp,SIGNAL(commandStarted(int)),

            this,SLOT(ftpCommandStarted(int)));

    //当每条命令开始执行时发出相应的信号

    connect(ftp,SIGNAL(commandFinished(int,bool)),

            this,SLOT(ftpCommandFinished(int,bool)));

//当每条命令执行结束时发出相应的信号

我们在构造函数里执行了几个FTP的操作,登录站点,并下载了一个文件。然后我们又关联了两个信号和槽,用来跟踪命令的执行情况。

(2)实现槽函数:

void Widget::ftpCommandStarted(int)

{

    if(ftp->currentCommand() == QFtp::ConnectToHost){

        ui->label->setText(tr(“正在连接到服务器…”));

    }

    if (ftp->currentCommand() == QFtp::Login){

        ui->label->setText(tr(“正在登录…”));

    }

    if (ftp->currentCommand() == QFtp::Get){

        ui->label->setText(tr(“正在下载…”));

    }

    else if (ftp->currentCommand() == QFtp::Close){

        ui->label->setText(tr(“正在关闭连接…”));

    }

}

每当命令执行时,都会执行ftpCommandStarted()函数,它有一个参数int id,这个id就是调用命令时返回的id,如int loginID = ftp->login(); 这时,我们就可以用if(id == loginID)来判断执行的是否是login()函数。但是,我们不想为每个命令都设置一个变量来存储其返回值,所以,我们这里使用了ftp->currentCommand() ,它也能获取当前执行的命令的类型。在这个函数里我们让开始不同的命令时显示不同的状态信息。

void Widget::ftpCommandFinished(int,bool error)

{

    if(ftp->currentCommand() == QFtp::ConnectToHost){

        if(error) ui->label->setText(tr(“连接服务器出现错误:%1″).arg(ftp->errorString()));

        else ui->label->setText(tr(“连接到服务器成功”));

    }

    if (ftp->currentCommand() == QFtp::Login){

        if(error) ui->label->setText(tr(“登录出现错误:%1″).arg(ftp->errorString()));

        else ui->label->setText(tr(“登录成功”));

    }

    if (ftp->currentCommand() == QFtp::Get){

        if(error) ui->label->setText(tr(“下载出现错误:%1″).arg(ftp->errorString()));

        else {

            ui->label->setText(tr(“已经完成下载”));

            ui->textBrowser->setText(ftp->readAll());

        }

    }

    else if (ftp->currentCommand() == QFtp::Close){

        ui->label->setText(tr(“已经关闭连接”));

    }

}

这个函数与ftpCommandStarted()函数相似,但是,它是在一个命令执行结束时执行的。它有两个参数,第一个int id,就是调用命令时返回的编号,我们在上面已经讲过了。第二个是bool error,它标志现在执行的命令是否出现了错误。如果出现了错误,那么error 为true ,否则为false。我们可以利用它来输出错误信息。在这个函数中,我们在完成一条命令时显示不同的状态信息,并显示可能的出错信息。在if (ftp->currentCommand() == QFtp::Get) 中,也就是已经完成下载时,我们让textBrowser显示下载的信息。

6.运行程序,效果如下。

登录状态。

 Hosted by ImageHost.org

下载完成后。

 Hosted by ImageHost.org

7.出错演示。

下面我们演示一下出错时的情况。

将构造函数中的代码ftp->login();改为ftp->login(“tom”,”123456″);

这时我们再运行程序:

 Hosted by ImageHost.org

可以看到,它输出了错误信息,指明了错误的指令和出错的内容。其实我们设置的这个错误,也是想告诉大家,在FTP中如果没有设置用户名和密码,那么默认的用户名应该是anonymous,这时密码可以任意填写,而使用其他用户名是会出错的。

     在下一节中,我们将会对这个程序进行扩展,让它可以浏览服务器上的所有文件,并进行下载。


http://www.niftyadmin.cn/n/790279.html

相关文章

信号量(Semaphore),倒计时器(CountDownlatch),屏障(CycliBarrier)

Semaphore 信号量控制一起进入线程的数量,通俗点讲是 synchronized 的加强版&#xff0c;作用是控制线程的并发数量 final Semaphore sh new Semaphore(2);//信号量为2for(int i 0; i < 3; i) {Thread tnew Thread(new Runnable() { public void run() { try {sh.acq…

Lucene4.3进阶开发之乱世丛生(二)

[b][colorred][sizex-large]转载请务必注明&#xff0c;原创地址&#xff0c;谢谢配合! [url]http://qindongliang1922.iteye.com/blog/1990616[/url] [/size][/color][/b][b][colorgreen][sizelarge]时间过的真快&#xff0c;又有半个月没更新lucene的文章了&#xff0c;散仙…

VMware虚拟机常见操作

VMware虚拟机中扩大Linux硬盘空间 ### 扩容空间 VMware 提供一个命令行工具&#xff0c;vmware-vdiskmanager.exe&#xff0c;位于vmware的安装目录下&#xff0c;在windows下运行cmd&#xff0c;转到 vmware 的安装目录&#xff0c;运行vmware-vdiskmanager.exe可以查看帮助, …

Hadoop2.2.0的eclipse插件的编译

[b][colorgreen][sizelarge]Hadoop2.x之后&#xff0c;已经发布了稳定的版本hadoop2.2.0.但是由于没有eclipse插件工具&#xff0c;辅助&#xff0c;开发调试相对起来&#xff0c;会稍显麻烦&#xff0c;特别是基于Java开发的工程师们&#xff0c;虽然写完MR任务后&#xff0c;…

用java验证连接MongoDB和SSM整合MongoDB(十二)

1、java连接MongoDB(通过客户端api的方式)进行操作 现在 MongoClient mongoClient new MongoClient(addrs,credentials); 方式已经删除了&#xff0c;不再用了&#xff0c;所以下面的连接方式有三种 (1)连接 方式一 MongoClientOptions.Builder builder MongoClientOptions…

详解 Qt 4访问Sqlite数据库

http://mobile.51cto.com/symbian-272807.htm 详解 Qt 4访问Sqlite数据库 2011-07-01 14:06 佚名 互联网 我要评论() 字号&#xff1a;T | TQt 4访问Sqlite数据库是本文要介绍的内容&#xff0c;先来认识一下sqlite&#xff0c;它是一款轻量级的、基于文件的嵌入式数据库 AD&am…

coradata 分页查找

分页读取数据库 class func DBGoodsInfoReadWithCondtions(limitData:Int,fetchSet:Int) -> [AnyObject]{ let app DBAppdalegateObject() let request NSFetchRequest() let entity NSEntityDescription.entityForName("GoodsInfo", inManagedObjectContext: …

java类加载(自定义类加载器)

类加载的功能&#xff1a; 创建自定义的类加载器&#xff0c;通过继承ClassLoader类&#xff0c;重写loadClass或者findClass即可。 推荐使用重写findClass&#xff0c;因为这样不会破坏 委托机制。 调用loadClass的时候&#xff0c;默认使用findClass找类。 看源码 public C…