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传输文件的案列。以及定时器的多种用法