Qt:多线程TCP服务器客户端双向文件互传,Server端和Client端分离(带进度 ...

打印 上一主题 下一主题

主题 531|帖子 531|积分 1593

Client 界面:


Server 界面:



Server 利用:

输入端口号后,点击启动监听
Client 利用:

1.毗连服务器

输入IP(服务器的IP所在)和端口号后,点击毗连按钮,毗连成功如下图所示:

2.向服务器发送文件

2.1 点击“选择当地文件”按钮,选择一个当地的文件。

2.2 点击“选择存储在服务器的目录”,选择发送的文件将要存储在服务器的哪个目录中。(此功能可直接在一台电脑上测试,当多台电脑的时候可以将目录改为服务器的现实目录所在)

2.3 点击“发送文件”按钮,即可开始向服务器传输文件,传输成功后客户端会有提示框。

3.下载服务器的文件(服务器向客户端发送文件)

3.1 点击“选择要下载的文件”按钮,选择想要下载的服务器下的文件(此功能可直接在一台电脑上测试,当多台电脑的时候可以将目录改为服务器的现实文件所在)。

3.2 点击“选择下载目录”按钮,选择下载文件的存储位置。

3.3 点击“下载文件”按钮,即可开始下载服务器的文件,下载成功后客户端会有提示框。



Server-Mainwindow焦点代码

  1.     //设置进度条
  2.     ui->progressBar->setRange(0,100);
  3.     ui->progressBar->setValue(0);
  4.     QWidget *progressWidget = new QWidget(this);
  5.     progressWidget->setLayout(new QHBoxLayout());
  6.     progressWidget->layout()->addWidget(ui->progressBar);
  7.     // 创建 QStatusBar
  8.     // 将小部件添加到 QStatusBar
  9.     ui->statusbar->addPermanentWidget(progressWidget);
  10.     // 设置主窗口的状态栏
  11.     setStatusBar(ui->statusbar);
  12.     ui->statusbar->setSizeGripEnabled(false);
  13.     //创建线程对象
  14.     QThread *thread = new QThread;
  15.     //创建任务对象
  16.     RecvFile *recvWork = new RecvFile;
  17.     //将任务对象移到子线程中
  18.     recvWork->moveToThread(thread);
  19.     connect(this,&MainWindow::startListen,recvWork,&RecvFile::startListen);
  20.     //更新进度条
  21.     connect(recvWork,&RecvFile::curPercent,ui->progressBar,&QProgressBar::setValue);
  22.     //启动线程
  23.     thread->start();
复制代码
Server-receiver.cpp焦点代码

  1. void RecvFile::startListen(unsigned short port)
  2. {
  3.     qDebug()<<port;
  4.     //分配内存空间
  5.     tcpServer = new QTcpServer(this);
  6.     tcpServer->listen(QHostAddress::Any,port);
  7.     connect(tcpServer,&QTcpServer::newConnection,[=]()
  8.     {
  9.         //取出建立好连接的套接字
  10.         tcpSocket = tcpServer->nextPendingConnection();
  11.         isStart = true;
  12.         connect(tcpSocket,&QTcpSocket::readyRead,this,&RecvFile::recvFile);
  13.         connect(tcpSocket,&QTcpSocket::disconnected,this,[=]()
  14.         {
  15.             //断开连接
  16.             tcpSocket->close();
  17.             tcpSocket->deleteLater();
  18.         });
  19.     });
  20. }
  21. void RecvFile:: recvFile()
  22. {
  23.     qDebug()<<"触发recvFile";
  24.     //取出接收的内容
  25.     QByteArray buf = tcpSocket->readAll();
  26.     if(true == isStart)//之前未接收文件的头部信息
  27.     {
  28.         //接收头部
  29.         qDebug()<<"接收头部===";
  30.         isStart = false;
  31.         //解析头部  buf的内容格式 <文件名>##<文件大小>
  32.         QString token=QString(buf).section("##",0,0);//token
  33.         qDebug()<<"token1="<<token;
  34.         recvfilesize = 0;//初始化已接收的文件长度为0
  35.         if(token=="197%*FILE*%197"){//是文件
  36.             qDebug()<<"文件";
  37.             filename = QString(buf).section("##",1,1);//文件名
  38.             filesize = QString(buf).section("##",2,2).toUInt();//文件大小
  39.             targetDir=QString(buf).section("##",3,3);//文件应存储的目录
  40.             qDebug()<<"filename="<<filename;
  41.             qDebug()<<"filesize="<<filesize;
  42.             qDebug()<<"targetDir="<<targetDir;
  43.         }
  44.         else if(token=="197%*DOWNLOAD*%197"){//请求下载文件信号
  45.             qDebug()<<"下载文件请求";
  46.             filePath = QString(buf).section("##",1,1);//文件完整路径
  47.             storagePath = QString(buf).section("##",2,2);//文件完整路径
  48.             qDebug()<<"filePath="<<filePath;
  49.             qDebug()<<"storagePath="<<storagePath;
  50.             isStart = true;//信号只是个头,不应该继续接收尾部
  51.             sendDownloadFile(filePath,storagePath);
  52.             return;
  53.         }
  54.         else if(token=="197%*CLIENT_RECEIVED*%197"){
  55.             qDebug()<<"客户端已成功接收文件";
  56.             isStart = true;//信号只是个头,不应该继续接收尾部
  57.             return;
  58.         }
  59.         else{
  60.             qDebug()<<"无效token!";
  61.             return;
  62.         }
  63.         filename=targetDir+"\"+filename;//设置文件位置
  64.         file.setFileName(filename);
  65.         qDebug()<<"filename="<<filename;
  66.         bool isOk = file.open(QIODevice::WriteOnly);
  67.         if(false == isOk)//打开失败
  68.         {
  69.             return;
  70.         }
  71.     }
  72.     else//文件的头部信息已经接收
  73.     {
  74.         qDebug()<<"接收尾部===";
  75.         qint64 len = file.write(buf);//将buf中的数据写入file文件,并返回实际写入的字节数。
  76.         if(len>0)
  77.         {
  78.             recvfilesize += len;//累计接收大小
  79.             int percent = ((recvfilesize)*100)/filesize;
  80.             //发出更新进度条的信号
  81.             //qDebug()<<"percent="<<percent;
  82.             emit curPercent(percent);
  83.         }
  84.         if(recvfilesize == filesize)
  85.         {
  86.             //emit recvOver();//接收完毕
  87.             qDebug()<<"接收完毕1";
  88.             file.close();
  89.             isStart = true;
  90.             //通知客户端 接收完毕
  91.             // 文件传输成功后发送文件接收完毕的信息给客户端
  92.             //============================================Token==================================================================
  93.             QString token="197%*SERVER_RECEIVED*%197";
  94.             //============================================Token==================================================================
  95.             QByteArray completionMessage = token.toUtf8();
  96.             completionMessage.append("##");
  97.             tcpSocket->write(completionMessage);
  98.             tcpSocket->waitForBytesWritten(); // 等待数据写入完毕
  99.         }
  100.         else{
  101.             qDebug()<<"recvfilesize != filesize";
  102.             //isStart = true;
  103.         }
  104.     }
  105. }
  106. void RecvFile::sendDownloadFile(QString path,QString targetDir)//发送头
  107. {
  108.     timer = new QTimer(this);
  109.     connect(timer,&QTimer::timeout,[=]()
  110.     {
  111.         //关闭定时器
  112.         timer->stop();
  113.         //发送文件数据
  114.         sendDownloadFileData();
  115.     });
  116.     file.setFileName(path);
  117.     //获取文件信息
  118.     QFileInfo info(path);
  119.     filesize = info.size();//获取文件大小
  120.     filename = info.fileName();//获取文件名
  121.     //============================================Token==================================================================
  122.     QString token="197%*FILE*%197";
  123.     //============================================Token==================================================================
  124.     //只读方式打开文件
  125.     bool isOk = file.open(QIODevice::ReadOnly);
  126.     if(true == isOk)
  127.     {
  128.         //创建文件头信息
  129.         QString head = QString("%1##%2##%3##%4").arg(token).arg(filename).arg(filesize).arg(targetDir);
  130.         //创建文件头信息,格式为"文件名##文件大小",例如 "example.txt##1024"
  131.         //发送头部信息
  132.         qint64 len = tcpSocket->write(head.toUtf8());
  133.         if(len>0)//发送成功
  134.         {
  135.             //防止tcp黏包问题,延时20ms
  136.             timer->start(20);
  137.         }
  138.         else
  139.         {
  140.             //发送失败
  141.             file.close();
  142.         }
  143.     }
  144.     else
  145.     {
  146.         QMessageBox::warning(nullptr,"错位","打开文件失败!");
  147.         return;
  148.     }
  149. }
复制代码



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美丽的神话

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表