Qt:多线程TCP服务器客户端双向文件互传,Server端和Client端分离(带进度
Client 界面:https://i-blog.csdnimg.cn/blog_migrate/7e00bff460412b4bcf20c7bacc980f7c.png
Server 界面:
https://i-blog.csdnimg.cn/blog_migrate/ebd1ab55d6d90411b667c8d08315b6c6.png
Server 利用:
输入端口号后,点击启动监听
Client 利用:
1.毗连服务器
输入IP(服务器的IP所在)和端口号后,点击毗连按钮,毗连成功如下图所示:
https://i-blog.csdnimg.cn/blog_migrate/9a3c76612621b6657fd0cde17f777c39.png
2.向服务器发送文件
2.1 点击“选择当地文件”按钮,选择一个当地的文件。
2.2 点击“选择存储在服务器的目录”,选择发送的文件将要存储在服务器的哪个目录中。(此功能可直接在一台电脑上测试,当多台电脑的时候可以将目录改为服务器的现实目录所在)
2.3 点击“发送文件”按钮,即可开始向服务器传输文件,传输成功后客户端会有提示框。
3.下载服务器的文件(服务器向客户端发送文件)
3.1 点击“选择要下载的文件”按钮,选择想要下载的服务器下的文件(此功能可直接在一台电脑上测试,当多台电脑的时候可以将目录改为服务器的现实文件所在)。
3.2 点击“选择下载目录”按钮,选择下载文件的存储位置。
3.3 点击“下载文件”按钮,即可开始下载服务器的文件,下载成功后客户端会有提示框。
Server-Mainwindow焦点代码
//设置进度条
ui->progressBar->setRange(0,100);
ui->progressBar->setValue(0);
QWidget *progressWidget = new QWidget(this);
progressWidget->setLayout(new QHBoxLayout());
progressWidget->layout()->addWidget(ui->progressBar);
// 创建 QStatusBar
// 将小部件添加到 QStatusBar
ui->statusbar->addPermanentWidget(progressWidget);
// 设置主窗口的状态栏
setStatusBar(ui->statusbar);
ui->statusbar->setSizeGripEnabled(false);
//创建线程对象
QThread *thread = new QThread;
//创建任务对象
RecvFile *recvWork = new RecvFile;
//将任务对象移到子线程中
recvWork->moveToThread(thread);
connect(this,&MainWindow::startListen,recvWork,&RecvFile::startListen);
//更新进度条
connect(recvWork,&RecvFile::curPercent,ui->progressBar,&QProgressBar::setValue);
//启动线程
thread->start(); Server-receiver.cpp焦点代码
void RecvFile::startListen(unsigned short port)
{
qDebug()<<port;
//分配内存空间
tcpServer = new QTcpServer(this);
tcpServer->listen(QHostAddress::Any,port);
connect(tcpServer,&QTcpServer::newConnection,[=]()
{
//取出建立好连接的套接字
tcpSocket = tcpServer->nextPendingConnection();
isStart = true;
connect(tcpSocket,&QTcpSocket::readyRead,this,&RecvFile::recvFile);
connect(tcpSocket,&QTcpSocket::disconnected,this,[=]()
{
//断开连接
tcpSocket->close();
tcpSocket->deleteLater();
});
});
}
void RecvFile:: recvFile()
{
qDebug()<<"触发recvFile";
//取出接收的内容
QByteArray buf = tcpSocket->readAll();
if(true == isStart)//之前未接收文件的头部信息
{
//接收头部
qDebug()<<"接收头部===";
isStart = false;
//解析头部buf的内容格式 <文件名>##<文件大小>
QString token=QString(buf).section("##",0,0);//token
qDebug()<<"token1="<<token;
recvfilesize = 0;//初始化已接收的文件长度为0
if(token=="197%*FILE*%197"){//是文件
qDebug()<<"文件";
filename = QString(buf).section("##",1,1);//文件名
filesize = QString(buf).section("##",2,2).toUInt();//文件大小
targetDir=QString(buf).section("##",3,3);//文件应存储的目录
qDebug()<<"filename="<<filename;
qDebug()<<"filesize="<<filesize;
qDebug()<<"targetDir="<<targetDir;
}
else if(token=="197%*DOWNLOAD*%197"){//请求下载文件信号
qDebug()<<"下载文件请求";
filePath = QString(buf).section("##",1,1);//文件完整路径
storagePath = QString(buf).section("##",2,2);//文件完整路径
qDebug()<<"filePath="<<filePath;
qDebug()<<"storagePath="<<storagePath;
isStart = true;//信号只是个头,不应该继续接收尾部
sendDownloadFile(filePath,storagePath);
return;
}
else if(token=="197%*CLIENT_RECEIVED*%197"){
qDebug()<<"客户端已成功接收文件";
isStart = true;//信号只是个头,不应该继续接收尾部
return;
}
else{
qDebug()<<"无效token!";
return;
}
filename=targetDir+"\\"+filename;//设置文件位置
file.setFileName(filename);
qDebug()<<"filename="<<filename;
bool isOk = file.open(QIODevice::WriteOnly);
if(false == isOk)//打开失败
{
return;
}
}
else//文件的头部信息已经接收
{
qDebug()<<"接收尾部===";
qint64 len = file.write(buf);//将buf中的数据写入file文件,并返回实际写入的字节数。
if(len>0)
{
recvfilesize += len;//累计接收大小
int percent = ((recvfilesize)*100)/filesize;
//发出更新进度条的信号
//qDebug()<<"percent="<<percent;
emit curPercent(percent);
}
if(recvfilesize == filesize)
{
//emit recvOver();//接收完毕
qDebug()<<"接收完毕1";
file.close();
isStart = true;
//通知客户端 接收完毕
// 文件传输成功后发送文件接收完毕的信息给客户端
//============================================Token==================================================================
QString token="197%*SERVER_RECEIVED*%197";
//============================================Token==================================================================
QByteArray completionMessage = token.toUtf8();
completionMessage.append("##");
tcpSocket->write(completionMessage);
tcpSocket->waitForBytesWritten(); // 等待数据写入完毕
}
else{
qDebug()<<"recvfilesize != filesize";
//isStart = true;
}
}
}
void RecvFile::sendDownloadFile(QString path,QString targetDir)//发送头
{
timer = new QTimer(this);
connect(timer,&QTimer::timeout,[=]()
{
//关闭定时器
timer->stop();
//发送文件数据
sendDownloadFileData();
});
file.setFileName(path);
//获取文件信息
QFileInfo info(path);
filesize = info.size();//获取文件大小
filename = info.fileName();//获取文件名
//============================================Token==================================================================
QString token="197%*FILE*%197";
//============================================Token==================================================================
//只读方式打开文件
bool isOk = file.open(QIODevice::ReadOnly);
if(true == isOk)
{
//创建文件头信息
QString head = QString("%1##%2##%3##%4").arg(token).arg(filename).arg(filesize).arg(targetDir);
//创建文件头信息,格式为"文件名##文件大小",例如 "example.txt##1024"
//发送头部信息
qint64 len = tcpSocket->write(head.toUtf8());
if(len>0)//发送成功
{
//防止tcp黏包问题,延时20ms
timer->start(20);
}
else
{
//发送失败
file.close();
}
}
else
{
QMessageBox::warning(nullptr,"错位","打开文件失败!");
return;
}
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]