TCP传文件流程图:
工程目录:
clientwidget.h:
#ifndef CLIENTWIDGET_H #define 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;//接收头文件标志 }; #endif // CLIENTWIDGET_H
serverwidget.h:
#ifndef SERVERWIDGET_H #define SERVERWIDGET_H #include <QWidget> #include <QTcpServer>//监听套接字 #include <QTcpSocket>//通信套接字 #include <QFile> #include <QTimer> namespace Ui { class serverWidget; } class serverWidget : public QWidget { Q_OBJECT public: 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;//定时器 }; #endif // SERVERWIDGET_H
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);//当前值 connect(tcpSocket,&QTcpSocket::readyRead,[=](){ //取出接收的内容 QByteArray buf = tcpSocket->readAll(); if (true == isStart) { //接收头 isStart = false; // 分段 0 0 1 1 2 2 //解析头部信息 buf = "hello##1024##333333" // QString str = "hello##1024"; // str.section("##",0,0);//这个拆出来hello,其中##是分段标识符,格式为:段1+标识符+段2+标识符+段3+标识符+…… //初始化 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 38 "; tcpSocket->disconnectFromHost();//断开连接 tcpSocket->close();//关闭套接字 return ;//如果打开文件失败,中断函数 } //弹出对话框,显示接收文件信息 QString str =QString("接收文件: [%1 : %2kb]").arg(fileName).arg(fileSize/1024); QMessageBox::information(this,"文件信息",str); //设置进度条 ui->progressBar->setMinimum(0);//最小值 ui->progressBar->setMaximum(fileSize/1024);//最大值 ui->progressBar->setValue(0);//当前值 } else//文件信息 { qint64 len = file.write(buf); if(len > 0) { recvSize += len;//累积接收大小 qDebug()<<len; } //更新进度条 ui->progressBar->setValue(recvSize/1024); if (recvSize == fileSize) { //先给服务发送(接收文件完成的消息) tcpSocket->write("file done "); QMessageBox::information(this,"完成","文件接收完毕"); file.close();//关闭文件 //断开连接 tcpSocket->disconnectFromHost(); tcpSocket->close(); } } }); } ClientWidget::~ClientWidget() { delete ui; } void ClientWidget::on_buttonConnect_clicked() { //获取服务器的ip和端口 QString ip = ui->lineEditIP->text(); qint16 port = ui->lineEditPort->text().toInt(); tcpSocket->connectToHost(QHostAddress(ip),port); }
main.cpp:
#include "serverwidget.h" #include <QApplication> #include "clientwidget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); serverWidget w; w.show(); ClientWidget w2; w2.show(); return a.exec(); }
serverwidget.cpp:
#include "serverwidget.h" #include "ui_serverwidget.h" #include <QFileDialog> #include <QDebug> 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); ui->buttonsend->setEnabled(true); connect(tcpSocket,&QTcpSocket::readyRead,[=](){ //取客户端信息 QByteArray buf = tcpSocket->readAll(); 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()<<"只读方式打开文件失败 78"; } //提示打开文件路径 ui->textEdit->append(filePath); ui->buttonFile->setEnabled(false); ui->buttonsend->setEnabled(true); } else { qDebug()<<"选择文件路径出错 62 "; } } //发送文件按钮按键 void serverWidget::on_buttonsend_clicked() { //先发送文件头信息 格式如:文件名##文件大小 QString head = QString("%1##%2").arg(fileName).arg(fileSize); //发送头部的信息 qint64 len = tcpSocket->write(head.toUtf8()); if (len > 0)//头部信息发送成功 { //发送真正的文件信息 //防止TCP黏包文件 //需要通过定时器延时 20ms timer.start(20); } else { qDebug()<<"头部信息发送失败 114"; file.close(); ui->buttonFile->setEnabled(true); ui->buttonsend->setEnabled(false); } } void serverWidget::sendData() { qint64 len = 0; do { //每次发送数据的大小 4K char buf[4*1024] = {0}; len = 0; //往文件中读数据 len = file.read(buf,sizeof(buf)); //发送数据,读多少 ,发多少 len = tcpSocket->write(buf,len); //发送的数据需要积累 sendSize += len; } while(len > 0); //是否发送文件完毕 if(sendSize == fileSize) { ui->textEdit->append("文件发送完毕"); file.close(); //把客户端关闭 tcpSocket->disconnectFromHost(); tcpSocket->close(); } }
clientwidget.ui:
serverwidget.ui: