QT学习(网络通讯:TCP)-2

QT学习(网络)

TCP

进入代码环节

***.pro

QT       += core gui network

界面如下:
在这里插入图片描述

在这里插入图片描述
***1.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtNetwork/QtNetwork>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_startButton_clicked();
    void start();   //开始监听
    void acceptConnection();  //建立连接
    void updateServerProgress();  //更新进度条,接收数据
    void displayError(QAbstractSocket::SocketError socketError);//显示错误

private:
    Ui::Widget *ui;
    QTcpServer tcpServer;
    QTcpSocket *tcpServerConnection;
    qint64 totalBytes;  //存放总大小信息
    qint64 bytesReceived;  //已收到数据的大小
    qint64 fileNameSize;  //文件名的大小信息
    QString fileName;   //存放文件名
    QFile *localFile;   //本地文件
    QByteArray inBlock;   //数据缓冲区
};

#endif // WIDGET_H

***1.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    totalBytes = 0;
    bytesReceived = 0;
    fileNameSize = 0;
    connect(&tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection()));//当发现新连接时发出newConnection()信号
}

Widget::~Widget()
{
    delete ui;
}

/******************************************************
    监听来自发送方的事件
    关联“开始监听”按钮
*******************************************************/
void Widget::start() //开始监听
{
    ui->startButton->setEnabled(false);
    bytesReceived =0;
    if(!tcpServer.listen(QHostAddress::LocalHost,6666))
    {
        qDebug() << tcpServer.errorString();
        close();
        return;
    }
    ui->serverStatusLabel->setText(tr("监听"));
}

/****************************************************************************
    实现接受连接
    关联updateServerProgress()和displayError(QAbstractSocket::SocketError) 函数
******************************************************************************/
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();
}

/*****************************************************************************
    实现更新进度条
    接收文件时提示:"接收文件 **** ..."
    接收完毕后提示: "接收文件 **** 成功!"
*******************************************************************************/
void Widget::updateServerProgress()  //更新进度条,接收数据
{
    QDataStream in(tcpServerConnection);
    in.setVersion(QDataStream::Qt_4_6);
    if(bytesReceived <= sizeof(qint64)*2)
    { //如果接收到的数据小于16个字节,那么是刚开始接收数据,我们保存到//来的头文件信息
        if((tcpServerConnection->bytesAvailable() >= sizeof(qint64)*2) && (fileNameSize == 0))
        {
            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)
    {  //如果接收的数据小于总数据,那么写入文件
        bytesReceived += tcpServerConnection->bytesAvailable();
        inBlock= tcpServerConnection->readAll();
        localFile->write(inBlock);
        inBlock.resize(0);
    }
    //更新进度条
    ui->serverProgressBar->setMaximum(totalBytes);
    ui->serverProgressBar->setValue(bytesReceived);

    if(bytesReceived == totalBytes)
    { //接收数据完成时
        tcpServerConnection->close();
        localFile->close();
        ui->startButton->setEnabled(true);
        ui->serverStatusLabel->setText(tr("接收文件 %1 成功!").arg(fileName));
    }
}

/****************************************
    实现错误处理函数
    出错则显示错误
    否则提示"服务端就绪"
******************************************/
void Widget::displayError(QAbstractSocket::SocketError) //错误处理
{
    qDebug() << tcpServerConnection->errorString();
    tcpServerConnection->close();
    ui->serverProgressBar->reset();
    ui->serverStatusLabel->setText(tr("服务端就绪"));
    ui->startButton->setEnabled(true);
}

/*******************************************
    “开始监听”按钮的单击事件
    关联 start(),负责监听
**********************************************/
void Widget::on_startButton_clicked() //开始监听按钮
{
    start();
}

***2.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtNetwork/QtNetwork>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void send();  //连接服务器
    void startTransfer();  //发送文件大小等信息
    void updateClientProgress(qint64); //发送数据,更新进度条
    void displayError(QAbstractSocket::SocketError); //显示错误
    void openFile();  //打开文件

    void on_openButton_clicked();

    void on_sendButton_clicked();

private:
    Ui::Widget *ui;
    QTcpSocket *tcpClient;
    QFile *localFile;  //要发送的文件
    qint64 totalBytes;  //数据总大小
    qint64 bytesWritten;  //已经发送数据大小
    qint64 bytesToWrite;   //剩余数据大小
    qint64 loadSize;   //每次发送数据的大小
    QString fileName;  //保存文件路径
    QByteArray outBlock;  //数据缓冲区,即存放每次要发送的数据
};

#endif // WIDGET_H



***2.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    loadSize = 4*1024;
    totalBytes = 0;
    bytesWritten = 0;
    bytesToWrite = 0;
    tcpClient = new QTcpSocket(this);

    connect(tcpClient,SIGNAL(connected()),this,SLOT(startTransfer()));//当连接服务器成功时,发出connected()信号,我们开始传送文件
    connect(tcpClient,SIGNAL(bytesWritten(qint64)),this,
            SLOT(updateClientProgress(qint64)));//当有数据发送成功时,我们更新进度条
    connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,
            SLOT(displayError(QAbstractSocket::SocketError)));
    ui->sendButton->setEnabled(false);//开始使”发送“按钮不可用
}

Widget::~Widget()
{
    delete ui;
}

/*************************************************
   “打开”按钮单击事件:选择在本机要发功的文件
   与“打开”按钮关联
   打开成功后,提示"打开文件 ***** 成功!"
***************************************************/
void Widget::openFile()   //打开文件
{
    fileName = QFileDialog::getOpenFileName(this);
    if(!fileName.isEmpty())
    {
        ui->sendButton->setEnabled(true);
        ui->clientStatusLabel->setText(tr("打开文件 %1 成功!").arg(fileName));
    }
}

/****************************************************
   “发送”按钮的单击事件:连接服务器
   与“发送”按钮关联
   主机:localhost
   端口:6666
****************************************************/
void Widget::send()   //连接到服务器,执行发送
{
    ui->sendButton->setEnabled(false);
    bytesWritten = 0;//初始化已发送字节为0
    ui->clientStatusLabel->setText(tr("连接中..."));
    tcpClient->connectToHost(ui->hostLineEdit->text(),ui->portLineEdit->text().toInt());//连接
}

/***************************************************
    实现文件头结构的发送
*****************************************************/
void Widget::startTransfer()  //实现文件大小等信息的发送
{
    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);//返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间
    sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2));//发送完头数据后剩余数据的大小

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

    ui->clientStatusLabel->setText(tr("已连接"));
    outBlock.resize(0);
}

/*******************************************************
    更新进度条,实现文件的传送
    每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,就发送剩余数据的大小
    实时更新发送进度
    发送完毕后,提示"传送文件 ***** 成功"
    如果没有发送任何数据,则关闭文件
*******************************************************/
void Widget::updateClientProgress(qint64 numBytes)
{
    //已经发送数据的大小
    bytesWritten += (int)numBytes;

    if(bytesToWrite > 0) //如果已经发送了数据
    {
        //每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,就发送剩余数据的大小
        outBlock = localFile->read(qMin(bytesToWrite,loadSize));

        bytesToWrite -= (int)tcpClient->write(outBlock);//发送完一次数据后还剩余数据的大小

        outBlock.resize(0);//清空发送缓冲区
    } else {
        localFile->close(); //如果没有发送任何数据,则关闭文件
    }

    //更新进度条
    ui->clientProgressBar->setMaximum(totalBytes);
    ui->clientProgressBar->setValue(bytesWritten);

    if(bytesWritten == totalBytes) //发送完毕
    {
        ui->clientStatusLabel->setText(tr("传送文件 %1 成功").arg(fileName));
        localFile->close();
        tcpClient->close();
    }
}

/****************************************
    实现错误处理函数
    出错则显示错误
    否则提示"客户端就绪"
******************************************/
void Widget::displayError(QAbstractSocket::SocketError) //显示错误
{
    qDebug() << tcpClient->errorString();
    tcpClient->close();
    ui->clientProgressBar->reset();
    ui->clientStatusLabel->setText(tr("客户端就绪"));
    ui->sendButton->setEnabled(true);
}

/*********************************************************
    “打开”按钮的单击事件
    关联 openFile(),负责打开本地文件
*******************************************************/
void Widget::on_openButton_clicked()//打开按钮
{
    openFile();
}

/***************************************************
    “发送”按钮的单击事件
    关联 send(),负责发送文件
******************************************************/
void Widget::on_sendButton_clicked()//发送按钮
{
    send();
}

学习链接:
网络Tcp2

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT 是一个很强大的跨平台应用程序开发框架,它提供了丰富的网络编程类库,可以很方便地实现 TCP 通讯。下面我们就来看一下 QT 中如何使用 TCP。 首先需要在代码中包含 `QTcpSocket` 和 `QTcpServer` 头文件: ```cpp #include <QTcpSocket> #include <QTcpServer> ``` ## TCP 客户端 TCP 客户端通常需要以下步骤: 1. 创建一个 `QTcpSocket` 对象; 2. 连接到服务器; 3. 发送数据; 4. 接收服务器返回的数据; 5. 断开连接。 下面是一个简单的 TCP 客户端的代码示例: ```cpp #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建 TCP socket 对象 QTcpSocket socket; // 连接到服务器 socket.connectToHost("127.0.0.1", 1234); if (!socket.waitForConnected()) { qDebug() << "Failed to connect to server!"; return -1; } // 发送数据 QByteArray data = "Hello, server!"; socket.write(data); socket.waitForBytesWritten(); // 接收数据 socket.waitForReadyRead(); QByteArray response = socket.readAll(); qDebug() << "Server response:" << response; // 断开连接 socket.close(); return a.exec(); } ``` 上面的代码中,我们首先创建了一个 `QTcpSocket` 对象,然后使用 `connectToHost` 函数连接到服务器。如果连接失败,会输出一条错误信息并退出程序。 接着,我们发送一条消息给服务器,使用 `write` 函数将数据写入 socket 缓冲区,并调用 `waitForBytesWritten` 等待数据发送完成。 然后,我们等待服务器返回数据,使用 `waitForReadyRead` 等待数据可读,并使用 `readAll` 函数将所有可读数据读取出来。 最后,我们关闭 socket 连接。 ## TCP 服务器 TCP 服务器通常需要以下步骤: 1. 创建一个 `QTcpServer` 对象; 2. 绑定服务器地址和端口; 3. 监听客户端连接; 4. 接收客户端数据; 5. 回复客户端数据; 6. 断开连接。 下面是一个简单的 TCP 服务器的代码示例: ```cpp #include <QTcpServer> #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建 TCP server 对象 QTcpServer server; // 绑定服务器地址和端口 if (!server.listen(QHostAddress::Any, 1234)) { qDebug() << "Failed to start server!"; return -1; } qDebug() << "Server started!"; while (server.isListening()) { // 监听客户端连接 QTcpSocket *socket = server.nextPendingConnection(); qDebug() << "New client connected:" << socket->peerAddress().toString(); // 接收客户端数据 socket->waitForReadyRead(); QByteArray data = socket->readAll(); qDebug() << "Received data from client:" << data; // 回复客户端数据 QByteArray response = "Hello, client!"; socket->write(response); socket->waitForBytesWritten(); // 断开连接 socket->close(); } return a.exec(); } ``` 上面的代码中,我们首先创建了一个 `QTcpServer` 对象,并使用 `listen` 函数绑定服务器地址和端口。如果绑定失败,会输出一条错误信息并退出程序。 然后,我们进入一个无限循环,使用 `nextPendingConnection` 函数监听客户端连接。当有新的客户端连接时,会输出一条提示信息,并返回一个 `QTcpSocket` 对象,用于与客户端通讯。 接着,我们使用 `waitForReadyRead` 等待客户端发送数据,并使用 `readAll` 函数读取所有可读数据。 然后,我们回复客户端数据,使用 `write` 函数将数据写入 socket 缓冲区,并调用 `waitForBytesWritten` 等待数据发送完成。 最后,我们关闭 socket 连接。 这就是 QT 中使用 TCP 的基本步骤,希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值