QT tcp与udp网络通信以及定时器的使用 (7)
QT tcp与udp网络通信以及定时器的使用
文章目录
- QT tcp与udp网络通信以及定时器的使用
- 1、QT网络与通信简单介绍
- 2、QT TCP通信
- 1、 服务器的流程
- 2、 客户端的流程
- 3、服务器的编写
- 4、客户端的编写
- 3、QT UDP通信
- 1、客户端流程
- 2、客户端编写
- 3、UDP广播
- 4、UDP组播
- 4、定时器的用法
- 1、方法一
- 2、方法2
- 2、方法3(不建议使用)
- 5、Tcp传文件
- 1、服务器编写
- 2、客户端编写
- 6、tcp与udp对比
- 7.总结
1、QT网络与通信简单介绍
QT5提供了一套完善的网络模块,包括了TCP、UDP、HTTP等协议的支持,可以方便地在QT应用程序中进行网络通信。通过QT5的网络模块,开发者可以实现客户端和服务器之间的数据传输、消息推送、远程控制等功能。
Qt中提供的所有的Socket类都是非阻塞的。
Qt中常用的用于socket通信的套接字类:
QTcpServer
用于TCP/IP通信, 作为服务器端套接字使用
QTcpSocket
用于TCP/IP通信,作为客户端套接字使用。
QUdpSocket
用于UDP通信,服务器,客户端均使用此套接字。
QSslSocket
用于实现安全的网络通信、
QWebSocket
用于实现WebSocket协议的通信等。
下面是继承关系:
2、QT TCP通信
TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为:TCP)是一种面向连接的、可靠的、基于字节流的通信协议。分为服务器与客户端。
1、 服务器的流程
2、 客户端的流程
总体双方的流程如下:
3、服务器的编写
完成的结果如下:客户端点击连接服务器按钮。成功连接就可以相互进行通信了。
注意,要使用QT的网络模块,需要在.pro文件中添加QT += network声明,以添加网络模块的依赖。
- 声明TCP监听套接字与通信套接字
#include <QTcpServer>
#include <QTcpSocket>
QTcpServer *pTcpListenSocket = nullptr;
QTcpSocket *pTcpCommunicatSocket = nullptr;
- 创建QTcpServer套接字。QTcpSocket套接字在客户端成功连接时获取。此时为空。
pTcpListenSocket = new QTcpServer(this);
pTcpCommunicatSocket = nullptr;
- 监听客户端连接请求并处理
pTcpListenSocket->listen(QHostAddress::Any, 7777); /* 服务器地址和端口 */
- 获取通信套接字
/* 取出建立好的连接套接字 */pTcpCommunicatSocket = pTcpListenSocket->nextPendingConnection();
- 最后就可以进行发送接收数据
/* 发送给客户端数据接口 */
pTcpCommunicatSocket->write(sendData);
/* 接收客户端的数据接口 */
QByteArray arry = pTcpCommunicatSocket->readAll();
- 断开连接
pTcpClientSocket->disconnectFromHost();
pTcpClientSocket->close();
服务器整体的代码如下:
首先Ui的布局:
serveridget.h
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Serveridget; }
QT_END_NAMESPACEclass Serveridget : public QWidget
{Q_OBJECTpublic:Serveridget(QWidget *parent = nullptr);~Serveridget();QString ip;quint16 port;
private:QTcpServer *pTcpListenSocket = nullptr;QTcpSocket *pTcpCommunicatSocket = nullptr;
private slots:void ConnecSucceSlot(void);void ReceDealSlot(void);void SendDataSlot(void);void DisServerSlot(void);void ClearReceSlot(void);void ClearSendSlot(void);
private:Ui::Serveridget *ui;
};
serveridget.cpp
#include "serveridget.h"
#include "ui_serveridget.h"
#include <QPushButton>
#include <QDebug>Serveridget::Serveridget(QWidget *parent): QWidget(parent), ui(new Ui::Serveridget)
{ui->setupUi(this);pTcpListenSocket = new QTcpServer(this);this->setWindowTitle("服务器端口:7777");this->resize(400,400);ui->textEditRead->setPlaceholderText("接收区");pTcpListenSocket->listen(QHostAddress::Any, 7777); /* 服务器地址和端口 *//* 客户端与服务器连接成功监听套接字会触发newConnection */connect(pTcpListenSocket, &QTcpServer::newConnection, this, &Serveridget::ConnecSucceSlot);/* 服务器发送数据 */connect(ui->pushButtonSendData, &QPushButton::pressed, this, &Serveridget::SendDataSlot);/* 断开与客户端的连接 */connect(ui->pushButtonClose, &QPushButton::pressed, this, &Serveridget::DisServerSlot);/* 清空接收区 */connect(ui->pushButtonClearSend, &QPushButton::pressed, this, &Serveridget::ClearSendSlot);/* 清空发送区 */connect(ui->pushButtonClearReceive, &QPushButton::pressed, this, &Serveridget::ClearReceSlot);}Serveridget::~Serveridget()
{delete ui;
}void Serveridget::ConnecSucceSlot(void)
{/* 取出建立好的连接套接字 */pTcpCommunicatSocket = pTcpListenSocket->nextPendingConnection();/* 获取连接成功客户端的ip与端口 */ip = pTcpCommunicatSocket->peerAddress().toString();port = pTcpCommunicatSocket->peerPort();QString str = QString("[%1]:[%2]:[%3]:连接成功").arg(ip).arg(port); /* 组包 */ui->textEditRead->setText(str); /* 显示连接成功 *//* 当客户端发送数据服务器成功接收通信套接字触发readyRead信号 */connect(pTcpCommunicatSocket, &QTcpSocket::readyRead, this, &Serveridget::ReceDealSlot);
}void Serveridget::ReceDealSlot(void)
{if (pTcpCommunicatSocket == nullptr) {return;}/* 接收客户端的数据 */QByteArray arry = pTcpCommunicatSocket->readAll();/* 显示数据 */ui->textEditRead->append(arry);
}void Serveridget::SendDataSlot(void)
{if (pTcpCommunicatSocket == nullptr) {return;}/* 获取发送的数据 */QByteArray sendData = ui->textEditWrite->toPlainText().toUtf8().data();/* 发送的数据 */pTcpCommunicatSocket->write(sendData);
}void Serveridget::DisServerSlot(void)
{if (pTcpCommunicatSocket == nullptr) {return;}/* 主动和客户端端口连接 */pTcpCommunicatSocket->disconnectFromHost();pTcpCommunicatSocket->close();pTcpCommunicatSocket = nullptr;QString str = QString("[%1]:[%2]:断开连接").arg(ip).arg(port); /* 组包 */ui->textEditRead->setText(str); /* 显示连接成功 */
}void Serveridget::ClearReceSlot(void)
{ui->textEditRead->clear();
}void Serveridget::ClearSendSlot(void)
{ui->textEditWrite->clear();
}
4、客户端的编写
- 声明TCP通信套接字
#include <QTcpSocket>
QTcpSocket *pTcpClientSocket = nullptr;
- 创建TCP通信套接字
pTcpClientSocket = new QTcpSocket(this);
- 主动与服务器建立连接
/* 主动与服务器建立连接 */
pTcpClientSocket->connectToHost(QHostAddress(ip), port);
- 读写数据
/* 发送数据给服务器 */
pTcpClientSocket->write(sendData);
/* 接收服务器的数据 */
QByteArray arry = pTcpClientSocket->readAll();
- 断开连接
pTcpClientSocket->disconnectFromHost();
pTcpClientSocket->close();
客户端整体的代码如下:
首先Ui的布局:
客户端的创建:
clientwidget.h
#include <QWidget>
#include <QTcpSocket>
namespace Ui {
class Clientwidget;
}
class Clientwidget : public QWidget
{Q_OBJECTpublic:explicit Clientwidget(QWidget *parent = nullptr);~Clientwidget();QTcpSocket *pTcpClientSocket = nullptr;
private slots:void ConnectServerSlot(void);void ConnectSucceSlot(void);void SendDataSlot(void);void ReadDataSlot(void);void DisconnectSlot(void);void DisconnecServerSlot(void);void ClearReceSlot(void);void ClearSendSlot(void);
private:Ui::Clientwidget *ui;
};
clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QPushButton>
#include <QHostAddress>Clientwidget::Clientwidget(QWidget *parent) :QWidget(parent),ui(new Ui::Clientwidget)
{ui->setupUi(this);pTcpClientSocket = new QTcpSocket(this);this->setWindowTitle("客户端");this->resize(400,400);ui->textEditRead->setPlaceholderText("接收区");/* 主动与服务器连接 */connect(ui->pushButtonConnect, &QPushButton::pressed, this, &Clientwidget::ConnectServerSlot);/* 如果成功与服务器建立连接通信套接字触发connected */connect(pTcpClientSocket, &QTcpSocket::connected, this, &Clientwidget::ConnectSucceSlot);/* 如果成功与服务器断开连接通信套接字触发disconnected */connect(pTcpClientSocket, &QTcpSocket::disconnected, this, &Clientwidget::DisconnectSlot);/* 接收服务器的数据 */connect(pTcpClientSocket, &QTcpSocket::readyRead, this, &Clientwidget::ReadDataSlot);/* 发送数据 */connect(ui->pushButtonsendData, &QPushButton::pressed, this, &Clientwidget::SendDataSlot);/* 断开与客户端的连接 */connect(ui->pushButtonDisconnec, &QPushButton::pressed,this, &Clientwidget::DisconnecServerSlot);/* 清空接收区 */connect(ui->pushButtonClearSend, &QPushButton::pressed, this, &Clientwidget::ClearSendSlot);/* 清空发送区 */connect(ui->pushButtonClearRece, &QPushButton::pressed, this, &Clientwidget::ClearReceSlot);
}Clientwidget::~Clientwidget()
{delete ui;
}void Clientwidget::ConnectServerSlot(void)
{/* 获取服务器ip和端口 */QString ip = ui->lineEditIP->text();qint16 port = ui->lineEditPort->text().toInt();/* 主动与服务器建立连接 */pTcpClientSocket->connectToHost(QHostAddress(ip), port);
}
void Clientwidget::ConnectSucceSlot(void)
{ui->textEditRead->append("成功与客户端连接");
}
void Clientwidget::SendDataSlot(void)
{/* 获取发送的数据 */QByteArray sendData = ui->textEditWrite->toPlainText().toUtf8().data();pTcpClientSocket->write(sendData);
}
void Clientwidget::ReadDataSlot(void)
{QByteArray arry = pTcpClientSocket->readAll();ui->textEditRead->append(arry);
}
void Clientwidget::DisconnectSlot(void)
{ui->textEditRead->append("断开与客户端连接");
}
void Clientwidget::DisconnecServerSlot(void)
{if (pTcpClientSocket == nullptr) {return;}pTcpClientSocket->disconnectFromHost();pTcpClientSocket->close();
}
void Clientwidget::ClearReceSlot(void)
{ui->textEditRead->clear();
}
void Clientwidget::ClearSendSlot(void)
{ui->textEditWrite->clear();
}
main.cpp
#include "serveridget.h"
#include "clientwidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{QApplication a(argc, argv);Serveridget serverWid;Clientwidget clientWid;serverWid.show();clientWid.show();return a.exec();
}
3、QT UDP通信
使用Qt提供的QUdpSocket进行UDP通信。在UDP方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发送数据。类似的服务器也不从客户端接收连接,只负责调用接收函数,等待来自客户端的数据的到达。
在UDP通信中,服务器端和客户端的概念已经显得有些淡化,两部分做的工作都大致相同.
1、客户端流程
创建其它的客户端也是一样的流程。
总体双方的流程如下:
2、客户端编写
注意,要使用QT的网络模块,需要在.pro文件中添加QT += network声明,以添加网络模块的依赖。
最后的效果如下:
客户端的ui界面:
- 声明UDP通信套接字
#include <QUdpSocket>
QUdpSocket *pUdpSocket = nullptr;
- 创建UDP通信套接字
pUdpSocket = new QUdpSocket(this);
- 绑定端口
pUdpSocket->bind(QHostAddress::Any,7777);
- 读写数据
/* 获取数据 */pUdpSocket->writeDatagram(sendData, QHostAddress(strIP), port);
/* 读取对方发送的内容 */
char buf[1024] = {0}; /* 保存对方的数据 */
QHostAddress cliAddr; /* 对方地址 */
quint16 port; /* 对方端口 */
qint64 size = pUdpSocket->readDatagram(buf, sizeof(buf), &cliAddr, &port);
总体的代码如下:
clientwidget.h
#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class ClientWidget; }
QT_END_NAMESPACE
class ClientWidget : public QWidget
{Q_OBJECTpublic:ClientWidget(QWidget *parent = nullptr);~ClientWidget();QUdpSocket *pUdpSocket = nullptr;
private slots:void ReadDataSlot(void);void WriteDataSlot(void);
private:Ui::ClientWidget *ui;
};
clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QPushButton>
#include <QDebug>ClientWidget::ClientWidget(QWidget *parent): QWidget(parent), ui(new Ui::ClientWidget)
{ui->setupUi(this);pUdpSocket = new QUdpSocket(this);/* 绑定端口 */pUdpSocket->bind(QHostAddress::Any,7777);this->setWindowTitle("服务器端口:7777");this->resize(400,400);ui->textEditRece->setPlaceholderText("接收区");/* 发送数据 */connect(ui->pushButtonSend, &QPushButton::pressed, this, &ClientWidget::WriteDataSlot);/* 接收到readyRead信号 */connect(pUdpSocket, &QUdpSocket::readyRead, this, &ClientWidget::ReadDataSlot);
}ClientWidget::~ClientWidget()
{delete ui;
}
void ClientWidget::WriteDataSlot(void)
{/* 获取发送对方的端口与IP */QString strIP = ui->lineEditIP->text();qint16 port = ui->lineEditPort->text().toInt();QByteArray sendData = ui->textEditSend->toPlainText().toUtf8().data();if (strIP.isEmpty() || sendData.size() == 0) {qDebug() << "isEmpty";return;}/* 获取数据 */pUdpSocket->writeDatagram(sendData, QHostAddress(strIP), port);
}void ClientWidget::ReadDataSlot(void)
{/* 读取对方发送的内容 */char buf[1024] = {0}; /* 保存对方的数据 */QHostAddress cliAddr; /* 对方地址 */quint16 port; /* 对方端口 */qint64 size = pUdpSocket->readDatagram(buf, sizeof(buf), &cliAddr, &port);qDebug() << "size:"<<size;if (size > 0) {/* 格式化 [192.68.2.2:8888]aaaa */QString str = QString("[%1:%2] %3").arg(cliAddr.toString()).arg(port).arg(buf);ui->textEditRece->append(str);}
}
例外一端是一样的。把绑定端口换一下就行。
pUdpSocket->bind(QHostAddress::Any,8888);
3、UDP广播
4、UDP组播
注意组播在绑定是IP要选择QHostAddress::AnyIPv4 并且组播是D类地址。
udpSocket->leaveMulticastGroup(QHostAddress(“224.0.0.2”)) 如果不想接收也可以退出这个组播。
4、定时器的用法
1、方法一
最后的效果:
只是简单使用两个不同的定时器。
1、定义一个QTimer对象
QTimer* timer;
timer = new QTimer(this);
- 启动定时器
timer->start(1000)
3 . 连接信号槽
当start启动定时器就会每隔设定的时间触发timeout信号
connect(timer, &QTimer::timeout,[=](){/* 定时器时间到的处理 */});
- 停止计时
timer->stop();
mywidget.h
#include <QWidget>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class MyWidget; }
QT_END_NAMESPACEclass MyWidget : public QWidget
{Q_OBJECT
public:MyWidget(QWidget *parent = nullptr);~MyWidget();QTimer *pTime_1;QTimer *pTime_2;int i = 0;int j = 0;private slots:void on_pushButtonStartOne_clicked();void on_pushButtonStartTwo_clicked();void on_pushButtonStopOne_clicked();void on_pushButtonStoptwo_clicked();private:Ui::MyWidget *ui;
};
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget)
{ui->setupUi(this);pTime_1 = new QTimer(this);pTime_2 = new QTimer(this);i = 0;j = 0;connect(pTime_1, &QTimer::timeout,[=](){i++;ui->lcdNumberOne->display(i);});connect(pTime_2, &QTimer::timeout,[=](){j++;ui->lcdNumberTwo->display(j);});
}MyWidget::~MyWidget()
{delete ui;
}
void MyWidget::on_pushButtonStartOne_clicked()
{//启动定时器//时间间隔为1s//每隔1s,定时器pTime_1自动触发timeout()//如果定时器没有激活,才启动if(pTime_1->isActive() == false){pTime_1->start(1000);}
}void MyWidget::on_pushButtonStartTwo_clicked()
{if(pTime_2->isActive() == false){pTime_2->start(1000);}
}void MyWidget::on_pushButtonStopOne_clicked()
{if(pTime_1->isActive() == true){pTime_1->stop();}
}void MyWidget::on_pushButtonStoptwo_clicked()
{if(pTime_2->isActive() == true){pTime_2->stop();}
}
2、方法2
1、重写虚函数
void timerEvent(QTimerEvent* e);
2、启动定时器
/* 返回定时器的Id 并且是唯一的 就是区分不同定时器 */
timeId_1 = startTimer(1000);
- 定时器时间到进入timerEvent事件
void MyWidget::timerEvent(QTimerEvent *e)
{static int i = 0;static int j = 0;if (e->timerId() == timeId_1) {ui->lcdNumberOne->display(++i);} else if (e->timerId()== timeId_2) {ui->lcdNumberTwo->display(++j);}
}
- 关闭定时器
killTimer(timeId_1);
mywidget.h
#include <QWidget>
#include <QTimerEvent>QT_BEGIN_NAMESPACE
namespace Ui { class MyWidget; }
QT_END_NAMESPACEclass MyWidget : public QWidget
{Q_OBJECTpublic:MyWidget(QWidget *parent = nullptr);~MyWidget();int timeId_1 = 0;int timeId_2 = 0;
protected:void timerEvent(QTimerEvent *e);
private slots:void on_pushButtonStartOne_clicked();void on_pushButtonStartTwo_clicked();void on_pushButtonStopOne_clicked();void on_pushButtonStoptwo_clicked();private:Ui::MyWidget *ui;
};
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget)
{ui->setupUi(this);}MyWidget::~MyWidget()
{delete ui;
}void MyWidget::timerEvent(QTimerEvent *e)
{static int i = 0;static int j = 0;if (e->timerId() == timeId_1) {ui->lcdNumberOne->display(++i);} else if (e->timerId()== timeId_2) {ui->lcdNumberTwo->display(++j);}
}void MyWidget::on_pushButtonStartOne_clicked()
{//启动定时器//时间间隔为1000ms//每隔1s,进入timerEvent事件timeId_1 = startTimer(1000);
}void MyWidget::on_pushButtonStartTwo_clicked()
{timeId_2 = startTimer(4000);
}void MyWidget::on_pushButtonStopOne_clicked()
{killTimer(timeId_1);
}void MyWidget::on_pushButtonStoptwo_clicked()
{killTimer(timeId_2);
}
2、方法3(不建议使用)
singleShot静态函数
原型:void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
解释:这个静态函数在一个给定时间间隔 msec(毫秒) 之后调用一个槽。
只调一次:
假设类A有个槽函数 function() { }
我们要在1s之后执行它
QTimer::singleShot(1000,this, &A::function())
实现循环:
槽函数中还是singleShot 即:
这样的话就是一个每1秒执行一次的定时器
bool condition = true;
function(){if(condition){ //条件控制QTimer::singleShot(1000,this, &A::function());}
}
5、Tcp传文件
具体的流程图如下:
最终的效果如下:
注意,要使用QT的网络模块,需要在.pro文件中添加QT += network声明,以添加网络模块的依赖。
1、服务器编写
服务器ui的设计:
serverwidget.h
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QTimer>namespace Ui {
class ServerWidget;
}class ServerWidget : public QWidget
{Q_OBJECTpublic:explicit ServerWidget(QWidget *parent = 0);~ServerWidget();void sendData(); //发送文件数据private slots:void on_buttonFile_clicked();void on_buttonSend_clicked();
private:Ui::ServerWidget *ui;QTcpServer *tcpServer; //监听套接字QTcpSocket *tcpSocket; //通信套接字QFile file; //文件对象QString fileName; //文件名字qint64 fileSize; //文件大小qint64 sendSize; //已经发送文件的大小QTimer timer; //定时器};
serverwidget.cpp
#include "serverwidget.h"
#include "ui_serverwidget.h"
#include <QFileDialog>#include <QFileInfo>ServerWidget::ServerWidget(QWidget *parent) :QWidget(parent),ui(new Ui::ServerWidget)
{ui->setupUi(this);/* 创建监听套接字 */tcpServer = new QTcpServer(this);/* 监听 */tcpServer->listen(QHostAddress::Any, 8888);/* 设置窗口标题 */setWindowTitle("服务器端口为:8888");/* 失能两个按钮都不能按 连接成功才可以按 */ui->buttonFile->setEnabled(false);ui->buttonSend->setEnabled(false);//如果客户端成功和服务器连接//tcpServer会自动触发 newConnection()connect(tcpServer, &QTcpServer::newConnection,[=](){//取出建立好连接的套接字tcpSocket = tcpServer->nextPendingConnection();//获取对方的ip和端口QString ip = tcpSocket->peerAddress().toString();quint16 port = tcpSocket->peerPort();QString str = QString("[%1:%2] 成功连接").arg(ip).arg(port);ui->textEdit->setText(str); //显示到编辑区//成功连接后,才能按选择文件ui->buttonFile->setEnabled(true);connect(tcpSocket, &QTcpSocket::readyRead,[=](){//取客户端的信息QByteArray buf = tcpSocket->readAll();/* 接收到客户端"file done" 说明客户端接收完成 */if(QString(buf) == "file done"){ //文件接收完毕ui->textEdit->append("文件发送完毕");file.close();//断开客户端端口tcpSocket->disconnectFromHost();tcpSocket->close();}});});connect(&timer, &QTimer::timeout,[=](){//关闭定时器timer.stop();//发送文件数据sendData();});}ServerWidget::~ServerWidget()
{delete ui;
}//选择文件的按钮
void ServerWidget::on_buttonFile_clicked()
{QString filePath = QFileDialog::getOpenFileName(this, "open", "../");if(false == filePath.isEmpty()) //如果选择文件路径有效{fileName.clear();fileSize = 0;QFileInfo info(filePath);//获取文件信息fileName = info.fileName(); //获取文件名字fileSize = info.size(); //获取文件大小sendSize = 0; //发送文件的大小//只读方式打开文件//指定文件的名字file.setFileName(filePath);//打开文件bool isOk = file.open(QIODevice::ReadOnly);if(false == isOk){qDebug() << "只读方式打开文件失败 106";}//提示打开文件的路径ui->textEdit->append(filePath);ui->buttonFile->setEnabled(false);ui->buttonSend->setEnabled(true);}else{qDebug() << "选择文件路径出错 118";}}
//发送文件按钮
void ServerWidget::on_buttonSend_clicked()
{ui->buttonSend->setEnabled(false);//先发送文件头信息 格式:文件名##文件大小QString head = QString("%1##%2").arg(fileName).arg(fileSize);//发送头部信息qint64 len = tcpSocket->write( head.toUtf8() );if(len > 0)//头部信息发送成功{//发送真正的文件信息//防止TCP黏包//需要通过定时器延时 20 ms 在发送文件数据timer.start(20);}else{qDebug() << "头部信息发送失败 142";file.close();ui->buttonFile->setEnabled(true);ui->buttonSend->setEnabled(false);}
}void ServerWidget::sendData()
{ui->textEdit->append("正在发送文件……");qint64 len = 0;do{//每次发送数据的大小 4Kchar buf[4*1024] = {0};len = 0;//往文件中读数据len = file.read(buf, sizeof(buf));//发送数据,读多少,发多少len = tcpSocket->write(buf, len);//发送的数据需要累积sendSize += len;}while(len > 0);}
2、客户端编写
客户端ui的设计:
功能:当客户端与服务器成功连接后。服务器选择发送一个文件给客户端。
clientwidget.h
#include <QWidget>
#include <QTcpSocket>
#include <QFile>namespace Ui {
class ClientWidget;
}class ClientWidget : public QWidget
{Q_OBJECT
public:explicit ClientWidget(QWidget *parent = 0);~ClientWidget();
private slots:void on_buttonConnect_clicked();
private:Ui::ClientWidget *ui;QTcpSocket *tcpSocket;QFile file; //文件对象QString fileName; //文件名字qint64 fileSize; //文件大小qint64 recvSize; //已经接收文件的大小bool isStart; //标志位,是否为头部信息
};
clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
//#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>ClientWidget::ClientWidget(QWidget *parent) :QWidget(parent),ui(new Ui::ClientWidget)
{ui->setupUi(this);tcpSocket = new QTcpSocket(this);isStart = true;ui->progressBar->setValue(0); //当前值setWindowTitle("客户端");connect(tcpSocket, &QTcpSocket::connected,[=](){//提示连接成功ui->textEdit->clear();ui->textEdit->append("和服务器连接成功,等待服务器传送文件……");});connect(tcpSocket, &QTcpSocket::readyRead,[=](){//取出接收的内容QByteArray buf = tcpSocket->readAll();if(true == isStart){//接收头isStart = false;//解析头部信息 QString buf = "hello##1024"// QString str = "hello##1024#mike";// str.section("##", 0, 0)//初始化//文件名fileName = QString(buf).section("##", 0, 0);//文件大小fileSize = QString(buf).section("##", 1, 1).toInt();recvSize = 0; //已经接收文件大小//打开文件//关联文件名字file.setFileName(fileName);//只写方式方式,打开文件bool isOk = file.open(QIODevice::WriteOnly);if(false == isOk){qDebug() << "WriteOnly error 49";tcpSocket->disconnectFromHost(); //断开连接tcpSocket->close(); //关闭套接字return; //如果打开文件失败退出。}//弹出对话框,显示接收文件的信息QString str = QString("接收的文件: [%1: %2kb]").arg(fileName).arg(fileSize/1024);//QMessageBox::information(this, "文件信息", str);ui->textEdit->append(str);ui->textEdit->append("正在接收文件……");//设置进度条ui->progressBar->setMinimum(0); //最小值ui->progressBar->setMaximum(fileSize/1024); //最大值ui->progressBar->setValue(0); //当前值}else //文件信息{qint64 len = file.write(buf);if(len >0) //接收数据大于0{recvSize += len; //累计接收大小qDebug() << len;}//更新进度条ui->progressBar->setValue(recvSize/1024); // 1024:防止文件太大越界 / 1024if(recvSize == fileSize) //文件接收完毕{//先给服务发送(接收文件完成的信息)tcpSocket->write("file done");ui->textEdit->append("文件接收完成");QMessageBox::information(this, "完成", "文件接收完成");file.close(); //关闭文件//断开连接tcpSocket->disconnectFromHost();tcpSocket->close();}}});
}ClientWidget::~ClientWidget()
{delete ui;
}void ClientWidget::on_buttonConnect_clicked()
{//获取服务器的ip和端口QString ip = ui->lineEditIP->text();quint16 port = ui->lineEditPort->text().toInt();//主动和服务器连接tcpSocket->connectToHost(QHostAddress(ip), port);isStart = true;//设置进度条ui->progressBar->setValue(0);
}
6、tcp与udp对比
7.总结
以上就是今天要讲的内容,本文简单介绍了QT的Tcp与udp网络通信。tcp传输文件的案列。以及定时器的多种用法
相关文章:

QT tcp与udp网络通信以及定时器的使用 (7)
QT tcp与udp网络通信以及定时器的使用 文章目录 QT tcp与udp网络通信以及定时器的使用1、QT网络与通信简单介绍2、QT TCP通信1、 服务器的流程2、 客户端的流程3、服务器的编写4、客户端的编写 3、QT UDP通信1、客户端流程2、客户端编写3、UDP广播4、UDP组播 4、定时器的用法1、…...
web架构师编辑器内容-添加自动保存的功能
对于频繁改动的应用,自动保存的功能是一个非常有用的功能,可以避免用户在没有保存的情况下丢失自己保存过的数据。 对于自动保存,一般有两种实现,参考语雀和石墨: 语雀采用的是定时保存的方式,大约在3分半…...

【Redis】关于它为什么快?使用场景?以及使用方式?为何引入多线程?
目录 1.既然redis那么快,为什么不用它做主数据库,只用它做缓存? 2.Redis 一般在什么场合下使用? 3.redis为什么这么快? 4.Redis为什么要引入了多线程? 1.既然redis那么快,为什么不用它做主数据…...

SpringBoot之JWT登录
JWT JSON Web Token(JSON Web令牌) 是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息。此信息可以验证和信任,因为它是数字签名的。jwt可以使用秘密〈使用HNAC算法…...

【备战蓝桥杯】——循环结构
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-bFHV3Dz5xMe6d3NB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...

【数据分享】1929-2023年全球站点的逐年平均气温数据(Shp\Excel\免费获取)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,其中又以气温指标最为常用!说到气温数据,最详细的气温数据是具体到气象监测站点的气温数据!本次我们为大家带来的就是具体到气象监…...

探索Pyecharts关系图绘制技巧:炫酷效果与创意呈现【第42篇—python:Pyecharts水球图】
文章目录 Pyecharts绘制多种炫酷关系网图引言准备工作代码实战1. 基本关系网图2. 自定义节点样式和边样式3. 关系网图的层级结构4. 添加标签和工具提示5. 动态关系网图6. 高级关系网图 - Les Miserables 示例7. 自定义关系网图布局8. 添加背景图9. 3D 关系网图10. 热力关系网图…...

蓝桥杯-循环节长度
两个整数做除法,有时会产生循环小数,其循环部分称为: 循环节。比如,11/136>0.8461553846153..... 其循环节为[846153] 共有 6 位。下面的方法,可以求出循环节的长度。请仔细阅读代码,并填写划线部分缺少的代码。 注…...
Jython调用openwire库连接activemq转发topic订阅消息到另一个activemq 服务器上 完整代码
以下是一个示例代码,演示如何在Jython中使用OpenWire库连接ActiveMQ,将一个主题(topic)上的订阅消息转发到另一个ActiveMQ服务器上: from org.apache.activemq import * from org.apache.activemq.transport import *…...
面试经典题---30.串联所有单词的子串
30.串联所有单词的子串 我的解法: 滑动窗口: 解法中用到了两个哈希表map1和map2,分别用于记录words中各个单词的出现频数和当前滑动窗口[left, right)中单词的出现频数;外部for循环i从0到len - 1,内部while循环每次会…...
字符串随机生成工具(开源)-Kimen(奇门)
由于最近笔者在开发数据脱敏相关功能,其中一类脱敏需求为能够按照指定的格式随机生成一个字符串来代替原有信息,数据看起来格式需要与原数据相同,如:电话号码,身份证号以及邮箱等。在网上搜索了下,发现没有…...

UE4 CustomDepthMobile流程小记
原生UE opaque材质中获取CustomDepth/CustomStencil会报错 在其Compile中调用的函数中没有看到报错逻辑 材质节点的逻辑都没有什么问题,所以看一下报错 在HLSLMaterialTranslator::Translate中 修改之后 mobile流程的不透明材质可以直接获取SceneTexture::customd…...

Docker 基础篇
目录 一、Docker 简介 1. Docker 2. Linux 容器 3. 传统虚拟机和容器的对比 4. Docker 的作用 5. Docker 的基本组成(Docker 三要素) 6. Docker 工作原理 7. Docker 架构 8. Docker 下载 二、Docker 安装 1. CentOS Docker 安装 2. CentOS8 …...

Idea上操作Git回退本地版本,怎么样保留已修改的文件,回退本地版本的四种方式代表什么?
Git的基本概念:Git是一个版本控制系统,用于管理代码的变更历史记录。核心概念包括仓库、分支、提交和合并。 1、可以帮助开发者合并开发的代码 2、如果出现冲突代码的合并,会提示后提交合并代码的开发者,让其解决冲突 3、代码文件版本管理 问题描述 当我们使用git提交代码…...

vue3封装el-pagination分页组件
1、效果如图: 2、分页组件代码: <template><div class"paging"><el-config-provider :locale"zhCn"><el-paginationv-model:current-page"page.currentPage"v-model:page-size"page.pageSize…...

负载均衡下Webshell连接思路及难点
君衍. 一、应用场景二、环境搭建三、思路以及难点1、查看内部结构2、查看webshell3、使用蚁剑进行连接4、难点1 shell文件上传问题5、难点2 命令执行时飘逸6、难点3 大工具上传失败7、难点4 脚本失效 四、解决方式1、关闭对方节点服务器2、基于IP地址判断是否执行3、脚本实现流…...

基于链表实现贪吃蛇游戏
本文中,我们将使用链表和一些Win32 API的知识来实现贪吃蛇小游戏 一、功能 (1)游戏载入界面 (2)地图的绘制 (3)蛇身的移动和变长 (4)食物的生成 (5&…...

Python网络爬虫实战——实验6:Python实现js逆向与加解密
【实验内容】 本实验主要介绍在数据采集过程中对js代码进行分析从而对加密字段进行解密。 【实验目的】 1、理解js逆向工程的概念 2、学会逆向工程中的加解密分析 【实验步骤】 步骤1 理解js逆向工程的概念 步骤2 学会逆向工程中的加解密分析 步骤3 采集广东政府采购网 步…...
【python】使用aiohttp库编写一个简单的异步服务器
1. aiohttp介绍 aiohttp 是一个用于编写异步 HTTP 客户端和服务器的 Python 库。它建立在 Python 的 asyncio 库之上,提供了一种方便的方式来处理异步请求和响应。 官网地址:Welcome to AIOHTTP — aiohttp 3.9.1 documentation 以下是 aiohttp 的一些…...

新手使用代理IP接入代码教程
“实现匿名访问与数据保护在当今互联网高速发展的时代,网络安全和隐私保护成为了越来越重要的议题。代理IP可以隐藏用户的真实IP地址,从而实现匿名访问。为了保护用户的隐私和数据安全,许多网站和应用程序都采用了代理IP技术。” 一、代理IP的…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...