久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

四十八,、Qt網(wǎng)絡(八)TCP(二)

 panhaosun 2011-04-21

本文章原創(chuàng)于 www. 轉(zhuǎn)載請注明出處。

在上一節(jié)里我們使用TCP服務器發(fā)送一個字符串,,然后在TCP客戶端進行接收,。在這一節(jié)我們重新寫一個客戶端程序和一個服務器程序,這次我們讓客戶端進行文件的發(fā)送,,服務器進行文件的接收,。有了上一節(jié)的基礎,這一節(jié)的內(nèi)容就很好理解了,,注意一下幾個信號和槽的關(guān)聯(lián)即可,。當然,我們這次要更深入了解一下數(shù)據(jù)的發(fā)送和接收的處理方法,。

一,、客戶端

這次我們先講解客戶端,在客戶端里我們與服務器進行連接,,一旦連接成功,,就會發(fā)出connected()信號,這時我們就進行文件的發(fā)送,。

在上一節(jié)我們已經(jīng)看到,,發(fā)送數(shù)據(jù)時我們先發(fā)送了數(shù)據(jù)的大小信息。這一次,,我們要先發(fā)送文件的總大小,,然后文件名長度,然后是文件名,,這三部分我們合稱為文件頭結(jié)構(gòu),,最后再發(fā)送文件數(shù)據(jù)。所以在發(fā)送函數(shù)里我們就要進行相應的處理,,當然,,在服務器的接收函數(shù)里我們也要進行相應的處理。對于文件大小,,這次我們使用了qint64,,它是64位的,,可以表示一個很大的文件了。

1.同前一節(jié),,我們新建工程,,將工程命名為“tcpSender”。注意添加network模塊,。

2.我們在widget.ui文件中將界面設計如下。

 Hosted by ImageHost.org

這里“主機”后的Line Edit的objectName為hostLineEdit,;“端口”后的Line Edit的objectName為portLineEdit,;下面的Progress Bar的objectName為clientProgressBar,其value屬性設為0,;“狀態(tài)”Label的objetName為clientStatusLabel,;“打開”按鈕的objectName為openButton;“發(fā)送”按鈕的objectName為sendButton;

3.在widget.h 文件中進行更改,。

(1)添加頭文件#include <QtNetwork>

(2)添加private變量:

QTcpSocket *tcpClient;

    QFile *localFile;  //要發(fā)送的文件

    qint64 totalBytes;  //數(shù)據(jù)總大小

    qint64 bytesWritten;  //已經(jīng)發(fā)送數(shù)據(jù)大小

    qint64 bytesToWrite;   //剩余數(shù)據(jù)大小

    qint64 loadSize;   //每次發(fā)送數(shù)據(jù)的大小

    QString fileName;  //保存文件路徑

QByteArray outBlock;  //數(shù)據(jù)緩沖區(qū),,即存放每次要發(fā)送的數(shù)據(jù)

(3)添加私有槽函數(shù):

private slots:

    void send();  //連接服務器

    void startTransfer();  //發(fā)送文件大小等信息

    void updateClientProgress(qint64); //發(fā)送數(shù)據(jù),更新進度條

    void displayError(QAbstractSocket::SocketError); //顯示錯誤

void openFile();  //打開文件

4.widget.cpp文件中進行更改,。

添加頭文件:#include <QFileDialog>

(1)在構(gòu)造函數(shù)中添加代碼:

loadSize = 4*1024;

    totalBytes = 0;

    bytesWritten = 0;

    bytesToWrite = 0;

    tcpClient = new QTcpSocket(this);

    connect(tcpClient,SIGNAL(connected()),this,SLOT(startTransfer()));

    //當連接服務器成功時,,發(fā)出connected()信號,我們開始傳送文件

    connect(tcpClient,SIGNAL(bytesWritten(qint64)),this,

SLOT(updateClientProgress(qint64)));

    //當有數(shù)據(jù)發(fā)送成功時,,我們更新進度條

    connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,

            SLOT(displayError(QAbstractSocket::SocketError)));

    ui->sendButton->setEnabled(false);

    //開始使”發(fā)送“按鈕不可用

我們主要是進行了變量的初始化和幾個信號和槽函數(shù)的關(guān)聯(lián),。

(2)實現(xiàn)打開文件函數(shù)。

void Widget::openFile()   //打開文件

{

    fileName = QFileDialog::getOpenFileName(this);

    if(!fileName.isEmpty())

    {

        ui->sendButton->setEnabled(true);

        ui->clientStatusLabel->setText(tr(“打開文件 %1 成功,!”)

                                       .arg(fileName));

    }

}

該函數(shù)將在下面的“打開”按鈕單擊事件槽函數(shù)中調(diào)用,。

(3)實現(xiàn)連接函數(shù)。

void Widget::send()   //連接到服務器,,執(zhí)行發(fā)送

{

    ui->sendButton->setEnabled(false);

    bytesWritten = 0;

    //初始化已發(fā)送字節(jié)為0

    ui->clientStatusLabel->setText(tr(“連接中…”));

    tcpClient->connectToHost(ui->hostLineEdit->text(),

                             ui->portLineEdit->text().toInt());//連接

}

該函數(shù)將在“發(fā)送”按鈕的單擊事件槽函數(shù)中調(diào)用,。

(4)實現(xiàn)文件頭結(jié)構(gòu)的發(fā)送。

void Widget::startTransfer()  //實現(xiàn)文件大小等信息的發(fā)送
{
    localFile = new QFile(fileName);
    if(!localFile->open(QFile::ReadOnly))
    {
        qDebug() << "open file error!";
        return;
    }
    totalBytes = localFile->size();
    //文件總大小
    QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_4_6);
    QString currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
    sendOut << qint64(0) << qint64(0) << currentFileName;
    //依次寫入總大小信息空間,,文件名大小信息空間,,文件名
    totalBytes += outBlock.size();
    //這里的總大小是文件名大小等信息和實際文件大小的總和
    sendOut.device()->seek(0);
    sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2));
    //返回outBolock的開始,用實際的大小信息代替兩個qint64(0)空間
    bytesToWrite = totalBytes - tcpClient->write(outBlock);
    //發(fā)送完頭數(shù)據(jù)后剩余數(shù)據(jù)的大小
    ui->clientStatusLabel->setText(tr("已連接"));
    outBlock.resize(0);
}

(5)下面是更新進度條,,也就是發(fā)送文件數(shù)據(jù),。

void Widget::updateClientProgress(qint64 numBytes) //更新進度條,實現(xiàn)文件的傳送

{

    bytesWritten += (int)numBytes;

    //已經(jīng)發(fā)送數(shù)據(jù)的大小

    if(bytesToWrite > 0) //如果已經(jīng)發(fā)送了數(shù)據(jù)

    {

        outBlock = localFile->read(qMin(bytesToWrite,loadSize));

      //每次發(fā)送loadSize大小的數(shù)據(jù),,這里設置為4KB,,如果剩余的數(shù)據(jù)不足4KB,

      //就發(fā)送剩余數(shù)據(jù)的大小

        bytesToWrite -= (int)tcpClient->write(outBlock);

       //發(fā)送完一次數(shù)據(jù)后還剩余數(shù)據(jù)的大小

        outBlock.resize(0);

        //清空發(fā)送緩沖區(qū)

    }

    else

    {

        localFile->close(); //如果沒有發(fā)送任何數(shù)據(jù),,則關(guān)閉文件

    }

    ui->clientProgressBar->setMaximum(totalBytes);

    ui->clientProgressBar->setValue(bytesWritten);

    //更新進度條

    if(bytesWritten == totalBytes) //發(fā)送完畢

    {

        ui->clientStatusLabel->setText(tr(“傳送文件 %1 成功”).arg(fileName));

        localFile->close();

        tcpClient->close();

    }

}

(6)實現(xiàn)錯誤處理函數(shù),。

void Widget::displayError(QAbstractSocket::SocketError) //顯示錯誤

{

    qDebug() << tcpClient->errorString();

    tcpClient->close();

    ui->clientProgressBar->reset();

    ui->clientStatusLabel->setText(tr(“客戶端就緒”));

    ui->sendButton->setEnabled(true);

}

(7)我們從widget.ui中分別進行“打開”按鈕和“發(fā)送”按鈕的單擊事件槽函數(shù),,然后更改如下。

void Widget::on_openButton_clicked() //打開按鈕

{

    openFile();

}

void Widget::on_sendButton_clicked() //發(fā)送按鈕

{

    send();

}

5.我們?yōu)榱耸钩绦蛑械闹形牟伙@示亂碼,,在main.cpp文件中更改,。

添加頭文件:#include <QTextCodec>

在main函數(shù)中添加代碼:QTextCodec::setCodecForTr(QTextCodec::codecForLocale());

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

 Hosted by ImageHost.org

7.程序整體思路分析,。

我們設計好界面,然后按下“打開”按鈕,,選擇我們要發(fā)送的文件,,這時調(diào)用了openFile()函數(shù)。然后我們點擊“發(fā)送”按鈕,,調(diào)用send()函數(shù),,與服務器進行連接。當連接成功時就會發(fā)出connected()信號,,這時就會執(zhí)行startTransfer()函數(shù),,進行文件頭結(jié)構(gòu)的發(fā)送,當發(fā)送成功時就會發(fā)出bytesWritten(qint64)信號,,這時我們執(zhí)行updateClientProgress(qint64 numBytes)進行文件數(shù)據(jù)的傳輸和進度條的更新,。這里使用了一個loadSize變量,我們在構(gòu)造函數(shù)中將其初始化為4*1024即4字節(jié),,它的作用是,,我們將整個大的文件分成很多小的部分進行發(fā)送,每部分為4字節(jié),。而當連接出現(xiàn)問題時就會發(fā)出error(QAbstractSocket::SocketError)信號,,這時就會執(zhí)行displayError()函數(shù)。對于程序中其他細節(jié)我們就不再分析,,希望大家能自己編程研究一下,。

二、服務器端,。

我們在服務器端進行數(shù)據(jù)的接收,。服務器端程序是很簡單的,我們開始進行監(jiān)聽,,一旦發(fā)現(xiàn)有連接請求就發(fā)出newConnection()信號,,然后我們便接受連接,開始接收數(shù)據(jù),。

1.新建工程,,名字為“tcpReceiver”。

2.我們更改widget.ui文件,,設計界面如下,。

其中“服務器端”Label的objectName為serverStatusLabel,;進度條Progress Bar的objectName為serverProgressBar,設置其value屬性為0,;“開始監(jiān)聽”按鈕的objectName為startButton,。

效果如下。

 Hosted by ImageHost.org

3.更改widget.h文件的內(nèi)容,。

(1)添加頭文件:#include <QtNetwork>

(2)添加私有變量:

     QTcpServer tcpServer;

    QTcpSocket *tcpServerConnection;

    qint64 totalBytes;  //存放總大小信息

    qint64 bytesReceived;  //已收到數(shù)據(jù)的大小

    qint64 fileNameSize;  //文件名的大小信息

    QString fileName;   //存放文件名

    QFile *localFile;   //本地文件

QByteArray inBlock;   //數(shù)據(jù)緩沖區(qū)

(3)添加私有槽函數(shù):

private slots:

    void on_startButton_clicked();

    void start();   //開始監(jiān)聽

    void acceptConnection();  //建立連接

    void updateServerProgress();  //更新進度條,,接收數(shù)據(jù)

void displayError(QAbstractSocket::SocketError socketError);

 //顯示錯誤

4.更改widget.cpp文件。

(1)在構(gòu)造函數(shù)中添加代碼:

totalBytes = 0;

    bytesReceived = 0;

    fileNameSize = 0;

    connect(&tcpServer,SIGNAL(newConnection()),this,

SLOT(acceptConnection()));

//當發(fā)現(xiàn)新連接時發(fā)出newConnection()信號

(2)實現(xiàn)start()函數(shù),。

void Widget::start() //開始監(jiān)聽

{

    ui->startButton->setEnabled(false);

    bytesReceived =0;

    if(!tcpServer.listen(QHostAddress::LocalHost,6666))

    {

        qDebug() << tcpServer.errorString();

        close();

        return;

    }

    ui->serverStatusLabel->setText(tr(“監(jiān)聽”));

}

(3)實現(xiàn)接受連接函數(shù),。

void Widget::acceptConnection()  //接受連接

{

    tcpServerConnection = tcpServer.nextPendingConnection();

connect(tcpServerConnection,SIGNAL(readyRead()),this,

SLOT(updateServerProgress()));

    connect(tcpServerConnection,

SIGNAL(error(QAbstractSocket::SocketError)),this,

            SLOT(displayError(QAbstractSocket::SocketError)));

    ui->serverStatusLabel->setText(tr(“接受連接”));

    tcpServer.close();

}

(4)實現(xiàn)更新進度條函數(shù)。

void Widget::updateServerProgress()  //更新進度條,,接收數(shù)據(jù)

{

   QDataStream in(tcpServerConnection);

   in.setVersion(QDataStream::Qt_4_6);

   if(bytesReceived <= sizeof(qint64)*2)

   { //如果接收到的數(shù)據(jù)小于16個字節(jié),那么是剛開始接收數(shù)據(jù),,我們保存到//來的頭文件信息

        if((tcpServerConnection->bytesAvailable() >= sizeof(qint64)*2)

            && (fileNameSize == 0))

        { //接收數(shù)據(jù)總大小信息和文件名大小信息

            in >> totalBytes >> fileNameSize;

            bytesReceived += sizeof(qint64) * 2;

        }

        if((tcpServerConnection->bytesAvailable() >= fileNameSize)

            && (fileNameSize != 0))

        {  //接收文件名,,并建立文件

            in >> fileName;

            ui->serverStatusLabel->setText(tr(“接收文件 %1 …”)

                                           .arg(fileName));

            bytesReceived += fileNameSize;

            localFile = new QFile(fileName);

            if(!localFile->open(QFile::WriteOnly))

            {

                qDebug() << “open file error!”;

                return;

            }

        }

        else return;

   }

   if(bytesReceived < totalBytes)

   {  //如果接收的數(shù)據(jù)小于總數(shù)據(jù),那么寫入文件

       bytesReceived += tcpServerConnection->bytesAvailable();

       inBlock = tcpServerConnection->readAll();

       localFile->write(inBlock);

       inBlock.resize(0);

   }

   ui->serverProgressBar->setMaximum(totalBytes);

   ui->serverProgressBar->setValue(bytesReceived);

   //更新進度條

   if(bytesReceived == totalBytes)

   { //接收數(shù)據(jù)完成時

    tcpServerConnection->close();

    localFile->close();

    ui->startButton->setEnabled(true);

ui->serverStatusLabel->setText(tr(“接收文件 %1 成功,!”)

.arg(fileName));

   }

}

(5)錯誤處理函數(shù),。

void Widget::displayError(QAbstractSocket::SocketError) //錯誤處理

{

    qDebug() << tcpServerConnection->errorString();

    tcpServerConnection->close();

    ui->serverProgressBar->reset();

    ui->serverStatusLabel->setText(tr(“服務端就緒”));

    ui->startButton->setEnabled(true);

}

(6)我們在widget.ui中進入“開始監(jiān)聽”按鈕的單擊事件槽函數(shù),更改如下,。

void Widget::on_startButton_clicked() //開始監(jiān)聽按鈕

{

    start();

}

5.我們?yōu)榱耸钩绦蛑械闹形牟伙@示亂碼,,在main.cpp文件中更改。

添加頭文件:#include <QTextCodec>

在main函數(shù)中添加代碼:QTextCodec::setCodecForTr(QTextCodec::codecForLocale());

6.運行程序,,并同時運行tcpSender程序,,效果如下。

 Hosted by ImageHost.org

我們先在服務器端按下“開始監(jiān)聽”按鈕,,然后在客戶端輸入主機地址和端口號,,然后打開要發(fā)送的文件,點擊“發(fā)送”按鈕進行發(fā)送,。

    在這兩節(jié)里我們介紹了TCP的應用,,可以看到服務器端和客戶度端都可以當做發(fā)送端或者接收端,而且數(shù)據(jù)的發(fā)送與接收只要使用相對應的協(xié)議即可,,它是可以根據(jù)用戶的需要來進行編程的,,沒有固定的格式。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多