zoukankan      html  css  js  c++  java
  • Qt学习之路_5(Qt TCP的初步使用)

           在上一篇博文Qt学习之路_4(Qt UDP的初步使用) 中,初步了解了Qt下UDP的使用,这一节就学习下TCP的使用。2者其实流程都差不多。当然了,本文还是参考的《Qt及Qt Quick开发实战精解》一书中的第5个例子,即局域网聊天工具中的UDP聊天和TCP文件传送部分。另外http://www.yafeilinux.com/ 上有其源码和相关教程下载。

             其发送端界面如下:

              

             接收端界面如下:

      

             发送端,也即承担服务器角色的操作:

             在主界面程序右侧选择一个需要发送文件的用户,弹出发送端界面后,点击打开按钮,在本地计算机中选择需要发送的文件,点击发送按钮,则进度条上会显示当前文件传送的信息,有已传送文件大小信息,传送速度等信息。如果想关闭发送过程,则单击关闭按钮。

             其流程图如下:

      

             接收端,也即承担客户端角色的操作:

             当在主界面中突然弹出一个对话框,问是否接自某个用户名和IP地址的文件传送信息,如果接受则单击yes按钮,否则就单击no按钮。当接收文件时,选择好接收文件所存目录和文件名后就开始接收文件了,其过程也会显示已接收文件的大小,接收速度和剩余时间的大小等信息。

             其流程图如下:

      

             TCP部分程序代码和注释如下:

     Widget.h:

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    
    class QUdpSocket;
    
    class TcpServer;//可以这样定义类?不用保护头文件的?
    
    namespace Ui {
    class Widget;
    }
    
    // 枚举变量标志信息的类型,分别为消息,新用户加入,用户退出,文件名,拒绝接受文件
    enum MessageType{Message, NewParticipant, ParticipantLeft, FileName, Refuse};
    
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    
    protected:
        void newParticipant(QString userName,
                            QString localHostName, QString ipAddress);
        void participantLeft(QString userName,
                             QString localHostName, QString time);
        void sendMessage(MessageType type, QString serverAddress="");
    
        QString getIP();
        QString getUserName();
        QString getMessage();
    
    
        void hasPendingFile(QString userName, QString serverAddress,
                            QString clientAddress, QString fileName);
    
    private:
        Ui::Widget *ui;
        QUdpSocket *udpSocket;
        qint16 port;
    
        QString fileName;
        TcpServer *server;
    
    private slots:
        void processPendingDatagrams();
    
        void on_sendButton_clicked();
    
        void getFileName(QString);
        void on_sendToolBtn_clicked();
    };
    
    #endif // WIDGET_H

    Widget.cpp:

    #include "widget.h"
    #include "ui_widget.h"
    #include <QUdpSocket>
    #include <QHostInfo>
    #include <QMessageBox>
    #include <QScrollBar>
    #include <QDateTime>
    #include <QNetworkInterface>
    #include <QProcess>
    
    #include "tcpserver.h"
    #include "tcpclient.h"
    #include <QFileDialog>
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        udpSocket = new QUdpSocket(this);
        port = 45454;
        udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
        connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
        sendMessage(NewParticipant);
    
        //TcpServer是tcpserver.ui对应的类,上面直接用QUdpSocket是因为没有单独的udpserver.ui类
        server = new TcpServer(this);
        //sendFileName()函数一发送,则触发槽函数getFileName()
        connect(server, SIGNAL(sendFileName(QString)), this, SLOT(getFileName(QString)));
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    // 使用UDP广播发送信息
    void Widget::sendMessage(MessageType type, QString serverAddress)
    {
        QByteArray data;
        QDataStream out(&data, QIODevice::WriteOnly);
        QString localHostName = QHostInfo::localHostName();
        QString address = getIP();
        out << type << getUserName() << localHostName;
    
        switch(type)
        {
        case Message :
            if (ui->messageTextEdit->toPlainText() == "") {
                QMessageBox::warning(0,tr("警告"),tr("发送内容不能为空"),QMessageBox::Ok);
                return;
            }
            out << address << getMessage();
            ui->messageBrowser->verticalScrollBar()
                    ->setValue(ui->messageBrowser->verticalScrollBar()->maximum());
            break;
    
        case NewParticipant :
            out << address;
            break;
    
        case ParticipantLeft :
            break;
    
        case FileName : {
            int row = ui->userTableWidget->currentRow();//必须选中需要发送的给谁才可以发送
            QString clientAddress = ui->userTableWidget->item(row, 2)->text();//(row,,2)为ip地址
            out << address << clientAddress << fileName;//发送本地ip,对方ip,所发送的文件名
            break;
        }
    
        case Refuse :
            out << serverAddress;
            break;
        }
        udpSocket->writeDatagram(data,data.length(),QHostAddress::Broadcast, port);
    }
    
    // 接收UDP信息
    void Widget::processPendingDatagrams()
    {
        while(udpSocket->hasPendingDatagrams())
        {
            QByteArray datagram;
            datagram.resize(udpSocket->pendingDatagramSize());
            udpSocket->readDatagram(datagram.data(), datagram.size());
            QDataStream in(&datagram, QIODevice::ReadOnly);
            int messageType;
            in >> messageType;
            QString userName,localHostName,ipAddress,message;
            QString time = QDateTime::currentDateTime()
                    .toString("yyyy-MM-dd hh:mm:ss");
    
            switch(messageType)
            {
            case Message:
                in >> userName >> localHostName >> ipAddress >> message;
                ui->messageBrowser->setTextColor(Qt::blue);
                ui->messageBrowser->setCurrentFont(QFont("Times New Roman",12));
                ui->messageBrowser->append("[ " +userName+" ] "+ time);
                ui->messageBrowser->append(message);
                break;
    
            case NewParticipant:
                in >>userName >>localHostName >>ipAddress;
                newParticipant(userName,localHostName,ipAddress);
                break;
    
            case ParticipantLeft:
                in >>userName >>localHostName;
                participantLeft(userName,localHostName,time);
                break;
    
            case FileName: {
                in >> userName >> localHostName >> ipAddress;
                QString clientAddress, fileName;
                in >> clientAddress >> fileName;
                hasPendingFile(userName, ipAddress, clientAddress, fileName);
                break;
            }
    
            case Refuse: {
                in >> userName >> localHostName;
                QString serverAddress;
                in >> serverAddress;
                QString ipAddress = getIP();
    
                if(ipAddress == serverAddress)
                {
                    server->refused();
                }
                break;
            }
            }
        }
    }
    
    // 处理新用户加入
    void Widget::newParticipant(QString userName, QString localHostName, QString ipAddress)
    {
        bool isEmpty = ui->userTableWidget->findItems(localHostName, Qt::MatchExactly).isEmpty();
        if (isEmpty) {
            QTableWidgetItem *user = new QTableWidgetItem(userName);
            QTableWidgetItem *host = new QTableWidgetItem(localHostName);
            QTableWidgetItem *ip = new QTableWidgetItem(ipAddress);
    
            ui->userTableWidget->insertRow(0);
            ui->userTableWidget->setItem(0,0,user);
            ui->userTableWidget->setItem(0,1,host);
            ui->userTableWidget->setItem(0,2,ip);
            ui->messageBrowser->setTextColor(Qt::gray);
            ui->messageBrowser->setCurrentFont(QFont("Times New Roman",10));
            ui->messageBrowser->append(tr("%1 在线!").arg(userName));
            ui->userNumLabel->setText(tr("在线人数:%1").arg(ui->userTableWidget->rowCount()));
    
            sendMessage(NewParticipant);
        }
    }
    
    // 处理用户离开
    void Widget::participantLeft(QString userName, QString localHostName, QString time)
    {
        int rowNum = ui->userTableWidget->findItems(localHostName, Qt::MatchExactly).first()->row();
        ui->userTableWidget->removeRow(rowNum);
        ui->messageBrowser->setTextColor(Qt::gray);
        ui->messageBrowser->setCurrentFont(QFont("Times New Roman", 10));
        ui->messageBrowser->append(tr("%1 于 %2 离开!").arg(userName).arg(time));
        ui->userNumLabel->setText(tr("在线人数:%1").arg(ui->userTableWidget->rowCount()));
    }
    
    // 获取ip地址
    QString Widget::getIP()
    {
        QList<QHostAddress> list = QNetworkInterface::allAddresses();
        foreach (QHostAddress address, list) {
            if(address.protocol() == QAbstractSocket::IPv4Protocol)
                return address.toString();
        }
        return 0;
    }
    
    // 获取用户名
    QString Widget::getUserName()
    {
        QStringList envVariables;
        envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
                     << "HOSTNAME.*" << "DOMAINNAME.*";
        QStringList environment = QProcess::systemEnvironment();
        foreach (QString string, envVariables) {
            int index = environment.indexOf(QRegExp(string));
            if (index != -1) {
                QStringList stringList = environment.at(index).split('=');
                if (stringList.size() == 2) {
                    return stringList.at(1);
                    break;
                }
            }
        }
        return "unknown";
    }
    
    // 获得要发送的消息
    QString Widget::getMessage()
    {
        QString msg = ui->messageTextEdit->toHtml();
    
        ui->messageTextEdit->clear();
        ui->messageTextEdit->setFocus();
        return msg;
    }
    
    
    // 发送消息
    void Widget::on_sendButton_clicked()
    {
        sendMessage(Message);
    }
    
    
    
    
    // 获取要发送的文件名
    void Widget::getFileName(QString name)
    {
        fileName = name;
        sendMessage(FileName);
    }
    
    // 传输文件按钮
    void Widget::on_sendToolBtn_clicked()
    {
        if(ui->userTableWidget->selectedItems().isEmpty())//传送文件前需选择用户
        {
            QMessageBox::warning(0, tr("选择用户"),
                           tr("请先从用户列表选择要传送的用户!"), QMessageBox::Ok);
            return;
        }
        server->show();
        server->initServer();
    }
    
    // 是否接收文件,客户端的显示
    void Widget::hasPendingFile(QString userName, QString serverAddress,
                                QString clientAddress, QString fileName)
    {
        QString ipAddress = getIP();
        if(ipAddress == clientAddress)
        {
            int btn = QMessageBox::information(this,tr("接受文件"),
                                               tr("来自%1(%2)的文件:%3,是否接收?")
                                               .arg(userName).arg(serverAddress).arg(fileName),
                                               QMessageBox::Yes,QMessageBox::No);//弹出一个窗口
            if (btn == QMessageBox::Yes) {
                QString name = QFileDialog::getSaveFileName(0,tr("保存文件"),fileName);//name为另存为的文件名
                if(!name.isEmpty())
                {
                    TcpClient *client = new TcpClient(this);
                    client->setFileName(name);    //客户端设置文件名
                    client->setHostAddress(QHostAddress(serverAddress));    //客户端设置服务器地址
                    client->show();
                }
            } else {
                sendMessage(Refuse, serverAddress);
            }
        }
    }

    Tcpserver.h:

    #ifndef TCPSERVER_H
    #define TCPSERVER_H
    
    #include <QDialog>
    
    #include <QTime>
    class QFile;
    class QTcpServer;
    class QTcpSocket;
    
    namespace Ui {
    class TcpServer;
    }
    
    class TcpServer : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit TcpServer(QWidget *parent = 0);
        ~TcpServer();
    
        void initServer();
        void refused();
    
    protected:
        void closeEvent(QCloseEvent *);
    
    private:
        Ui::TcpServer *ui;
    
        qint16 tcpPort;
        QTcpServer *tcpServer;
        QString fileName;
        QString theFileName;
        QFile *localFile;
    
        qint64 TotalBytes;
        qint64 bytesWritten;
        qint64 bytesToWrite;
        qint64 payloadSize;
        QByteArray outBlock;
    
        QTcpSocket *clientConnection;
    
        QTime time;
    
    private slots:
        void sendMessage();
        void updateClientProgress(qint64 numBytes);
    
        void on_serverOpenBtn_clicked();
    
        void on_serverSendBtn_clicked();
    
        void on_serverCloseBtn_clicked();
    
    signals:
        void sendFileName(QString fileName);
    };
    
    #endif // TCPSERVER_H

    Tcpserver.cpp:

    #include "tcpserver.h"
    #include "ui_tcpserver.h"
    
    #include <QFile>
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QMessageBox>
    #include <QFileDialog>
    #include <QDebug>
    
    TcpServer::TcpServer(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::TcpServer)
    {
        ui->setupUi(this);    //每一个新类都有一个自己的ui
    
        setFixedSize(350,180);    //初始化时窗口显示固定大小
    
        tcpPort = 6666;        //tcp通信端口
        tcpServer = new QTcpServer(this);
        //newConnection表示当tcp有新连接时就发送信号
        connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendMessage()));
    
        initServer();
    }
    
    TcpServer::~TcpServer()
    {
        delete ui;
    }
    
    // 初始化
    void TcpServer::initServer()
    {
        payloadSize = 64*1024;
        TotalBytes = 0;
        bytesWritten = 0;
        bytesToWrite = 0;
    
        ui->serverStatusLabel->setText(tr("请选择要传送的文件"));
        ui->progressBar->reset();//进度条复位
        ui->serverOpenBtn->setEnabled(true);//open按钮可用
        ui->serverSendBtn->setEnabled(false);//发送按钮不可用
    
        tcpServer->close();//tcp传送文件窗口不显示
    }
    
    // 开始发送数据
    void TcpServer::sendMessage()    //是connect中的槽函数
    {
        ui->serverSendBtn->setEnabled(false);    //当在传送文件的过程中,发送按钮不可用
        clientConnection = tcpServer->nextPendingConnection();    //用来获取一个已连接的TcpSocket
        //bytesWritten为qint64类型,即长整型
        connect(clientConnection, SIGNAL(bytesWritten(qint64)),    //?
                this, SLOT(updateClientProgress(qint64)));
    
        ui->serverStatusLabel->setText(tr("开始传送文件 %1 !").arg(theFileName));
    
        localFile = new QFile(fileName);    //localFile代表的是文件内容本身
        if(!localFile->open((QFile::ReadOnly))){
            QMessageBox::warning(this, tr("应用程序"), tr("无法读取文件 %1:\n%2")
                                 .arg(fileName).arg(localFile->errorString()));//errorString是系统自带的信息
            return;
        }
        TotalBytes = localFile->size();//文件总大小
        //头文件中的定义QByteArray outBlock;
        QDataStream sendOut(&outBlock, QIODevice::WriteOnly);//设置输出流属性
        sendOut.setVersion(QDataStream::Qt_4_7);//设置Qt版本,不同版本的数据流格式不同
        time.start();  // 开始计时
        QString currentFile = fileName.right(fileName.size()    //currentFile代表所选文件的文件名
                                             - fileName.lastIndexOf('/')-1);
        //qint64(0)表示将0转换成qint64类型,与(qint64)0等价
        //如果是,则此处为依次写入总大小信息空间,文件名大小信息空间,文件名
        sendOut << qint64(0) << qint64(0) << currentFile;
        TotalBytes += outBlock.size();//文件名大小等信息+实际文件大小
        //sendOut.device()为返回io设备的当前设置,seek(0)表示设置当前pos为0
        sendOut.device()->seek(0);//返回到outBlock的开始,执行覆盖操作
        //发送总大小空间和文件名大小空间
        sendOut << TotalBytes << qint64((outBlock.size() - sizeof(qint64)*2));
        //qint64 bytesWritten;bytesToWrite表示还剩下的没发送完的数据
        //clientConnection->write(outBlock)为套接字将内容发送出去,返回实际发送出去的字节数
        bytesToWrite = TotalBytes - clientConnection->write(outBlock);
        outBlock.resize(0);//why??
    }
    
    // 更新进度条,有数据发送时触发
    void TcpServer::updateClientProgress(qint64 numBytes)
    {
        //qApp为指向一个应用对象的全局指针
        qApp->processEvents();//processEvents为处理所有的事件?
        bytesWritten += (int)numBytes;
        if (bytesToWrite > 0) {    //没发送完毕
            //初始化时payloadSize = 64*1024;qMin为返回参数中较小的值,每次最多发送64K的大小
            outBlock = localFile->read(qMin(bytesToWrite, payloadSize));
            bytesToWrite -= (int)clientConnection->write(outBlock);
            outBlock.resize(0);//清空发送缓冲区
        } else {
            localFile->close();
        }
        ui->progressBar->setMaximum(TotalBytes);//进度条的最大值为所发送信息的所有长度(包括附加信息)
        ui->progressBar->setValue(bytesWritten);//进度条显示的进度长度为bytesWritten实时的长度
    
        float useTime = time.elapsed();//从time.start()还是到当前所用的时间记录在useTime中
        double speed = bytesWritten / useTime;
        ui->serverStatusLabel->setText(tr("已发送 %1MB (%2MB/s) "
                       "\n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
                       .arg(bytesWritten / (1024*1024))    //转化成MB
                       .arg(speed*1000 / (1024*1024), 0, 'f', 2)
                       .arg(TotalBytes / (1024 * 1024))
                       .arg(useTime/1000, 0, 'f', 0)    //0,‘f’,0是什么意思啊?
                       .arg(TotalBytes/speed/1000 - useTime/1000, 0, 'f', 0));
    
        if(bytesWritten == TotalBytes) {    //当需发送文件的总长度等于已发送长度时,表示发送完毕!
            localFile->close();
            tcpServer->close();
            ui->serverStatusLabel->setText(tr("传送文件 %1 成功").arg(theFileName));
        }
    }
    
    // 打开按钮
    void TcpServer::on_serverOpenBtn_clicked()
    {
        //QString fileName;QFileDialog是一个提供给用户选择文件或目录的对话框
        fileName = QFileDialog::getOpenFileName(this);    //filename为所选择的文件名(包含了路径名)
        if(!fileName.isEmpty())
        {
            //fileName.right为返回filename最右边参数大小个字文件名,theFileName为所选真正的文件名
            theFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
            ui->serverStatusLabel->setText(tr("要传送的文件为:%1 ").arg(theFileName));
            ui->serverSendBtn->setEnabled(true);//发送按钮可用
            ui->serverOpenBtn->setEnabled(false);//open按钮禁用
        }
    }
    
    // 发送按钮
    void TcpServer::on_serverSendBtn_clicked()
    {
        //tcpServer->listen函数如果监听到有连接,则返回1,否则返回0
        if(!tcpServer->listen(QHostAddress::Any,tcpPort))//开始监听6666端口
        {
            qDebug() << tcpServer->errorString();//此处的errorString是指?
            close();
            return;
        }
    
        ui->serverStatusLabel->setText(tr("等待对方接收... ..."));
        emit sendFileName(theFileName);//发送已传送文件的信号,在widget.cpp构造函数中的connect()触发槽函数
    }
    
    // 关闭按钮,服务器端的关闭按钮
    void TcpServer::on_serverCloseBtn_clicked()
    {
        if(tcpServer->isListening())
        {
            //当tcp正在监听时,关闭tcp服务器端应用,即按下close键时就不监听tcp请求了
            tcpServer->close();
            if (localFile->isOpen())//如果所选择的文件已经打开,则关闭掉
                localFile->close();
            clientConnection->abort();//clientConnection为下一个连接?怎么理解
        }
        close();//关闭本ui,即本对话框
    }
    
    // 被对方拒绝
    void TcpServer::refused()
    {
        tcpServer->close();
        ui->serverStatusLabel->setText(tr("对方拒绝接收!!!"));
    }
    
    // 关闭事件
    void TcpServer::closeEvent(QCloseEvent *)
    {
        on_serverCloseBtn_clicked();
    }

    Tcpclient.h:

    #ifndef TCPCLIENT_H
    #define TCPCLIENT_H
    
    #include <QDialog>
    #include <QHostAddress>
    #include <QFile>
    #include <QTime>
    class QTcpSocket;
    
    namespace Ui {
    class TcpClient;
    }
    
    class TcpClient : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit TcpClient(QWidget *parent = 0);
        ~TcpClient();
    
        void setHostAddress(QHostAddress address);
        void setFileName(QString fileName);
    
    protected:
        void closeEvent(QCloseEvent *);
    
    private:
        Ui::TcpClient *ui;
    
        QTcpSocket *tcpClient;
        quint16 blockSize;
        QHostAddress hostAddress;
        qint16 tcpPort;
    
        qint64 TotalBytes;
        qint64 bytesReceived;
        qint64 bytesToReceive;
        qint64 fileNameSize;
        QString fileName;
        QFile *localFile;
        QByteArray inBlock;
    
        QTime time;
    
    private slots:
        void on_tcpClientCancleBtn_clicked();
        void on_tcpClientCloseBtn_clicked();
    
        void newConnect();
        void readMessage();
        void displayError(QAbstractSocket::SocketError);
    };
    
    #endif // TCPCLIENT_H

    Tcpclient.cpp:

    #include "tcpclient.h"
    #include "ui_tcpclient.h"
    
    #include <QTcpSocket>
    #include <QDebug>
    #include <QMessageBox>
    
    TcpClient::TcpClient(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::TcpClient)
    {
        ui->setupUi(this);
    
        setFixedSize(350,180);
    
        TotalBytes = 0;
        bytesReceived = 0;
        fileNameSize = 0;
    
        tcpClient = new QTcpSocket(this);
        tcpPort = 6666;
        connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readMessage()));
        connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)), this,
                SLOT(displayError(QAbstractSocket::SocketError)));
    }
    
    TcpClient::~TcpClient()
    {
        delete ui;
    }
    
    // 设置文件名
    void TcpClient::setFileName(QString fileName)
    {
        localFile = new QFile(fileName);
    }
    
    // 设置地址
    void TcpClient::setHostAddress(QHostAddress address)
    {
        hostAddress = address;
        newConnect();
    }
    
    // 创建新连接
    void TcpClient::newConnect()
    {
        blockSize = 0;
        tcpClient->abort();        //取消已有的连接
        tcpClient->connectToHost(hostAddress, tcpPort);//连接到指定ip地址和端口的主机
        time.start();
    }
    
    // 读取数据
    void TcpClient::readMessage()
    {
        QDataStream in(tcpClient);    //这里的QDataStream可以直接用QTcpSocket对象做参数
        in.setVersion(QDataStream::Qt_4_7);
    
        float useTime = time.elapsed();
    
        if (bytesReceived <= sizeof(qint64)*2) {    //说明刚开始接受数据
            if ((tcpClient->bytesAvailable()    //bytesAvailable为返回将要被读取的字节数
                 >= sizeof(qint64)*2) && (fileNameSize == 0))
            {
                //接受数据总大小信息和文件名大小信息
                in>>TotalBytes>>fileNameSize;
                bytesReceived += sizeof(qint64)*2;
            }
            if((tcpClient->bytesAvailable() >= fileNameSize) && (fileNameSize != 0)){
                //开始接受文件,并建立文件
                in>>fileName;
                bytesReceived +=fileNameSize;
    
                if(!localFile->open(QFile::WriteOnly)){
                    QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2.")
                                         .arg(fileName).arg(localFile->errorString()));
                    return;
                }
            } else {
                return;
            }
        }
        if (bytesReceived < TotalBytes) {
            bytesReceived += tcpClient->bytesAvailable();//返回tcpClient中字节的总数
            inBlock = tcpClient->readAll();    //返回读到的所有数据
            localFile->write(inBlock);
            inBlock.resize(0);
        }
        ui->progressBar->setMaximum(TotalBytes);
        ui->progressBar->setValue(bytesReceived);
    
        double speed = bytesReceived / useTime;
        ui->tcpClientStatusLabel->setText(tr("已接收 %1MB (%2MB/s) "
                                             "\n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
                                          .arg(bytesReceived / (1024*1024))
                                          .arg(speed*1000/(1024*1024),0,'f',2)
                                          .arg(TotalBytes / (1024 * 1024))
                                          .arg(useTime/1000,0,'f',0)
                                          .arg(TotalBytes/speed/1000 - useTime/1000,0,'f',0));
    
        if(bytesReceived == TotalBytes)
        {
            localFile->close();
            tcpClient->close();
            ui->tcpClientStatusLabel->setText(tr("接收文件 %1 完毕")
                                              .arg(fileName));
        }
    }
    
    // 错误处理
    //QAbstractSocket类提供了所有scoket的通用功能,socketError为枚举型
    void TcpClient::displayError(QAbstractSocket::SocketError socketError)
    {
        switch(socketError)
        {
        //RemoteHostClosedError为远处主机关闭了连接时发出的错误信号
        case QAbstractSocket::RemoteHostClosedError : break;
        default : qDebug() << tcpClient->errorString();
        }
    }
    
    // 取消按钮
    void TcpClient::on_tcpClientCancleBtn_clicked()
    {
        tcpClient->abort();
        if (localFile->isOpen())
            localFile->close();
    }
    
    // 关闭按钮
    void TcpClient::on_tcpClientCloseBtn_clicked()
    {
        tcpClient->abort();
        if (localFile->isOpen())
            localFile->close();
        close();
    }
    
    // 关闭事件
    void TcpClient::closeEvent(QCloseEvent *)
    {
        on_tcpClientCloseBtn_clicked();
    }

    Main.cpp:

    #include <QtGui/QApplication>
    #include "widget.h"
    #include <QTextCodec>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
        Widget w;
        w.show();
    
        return a.exec();
    }
    作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:tornadomeet,欢迎交流!)
  • 相关阅读:
    搜集整理一些Cron表达式例子
    正确处理下载文件时HTTP头的编码问题(Content-Disposition)
    SpringMVC之RequestContextHolder分析
    协变、逆变与不变:数组、泛型、与返回类型
    用java实现一个简单的单用户登陆功能的思路
    为什么要进行URL编码
    spring mvc&mybatis搭配使用心得
    css(二)
    css(一)
    html
  • 原文地址:https://www.cnblogs.com/tornadomeet/p/2571001.html
Copyright © 2011-2022 走看看