借助上一篇文章的内容,在原有的TCP通讯的基础上,在服务端和客户端之间发送文件。
首先把在客户端加一个用于显示发送进度的进度条,在服务器端把原有的发送和关闭换为选择和发送,如下图所示
在客户端连接服务器之后建立套接字,服务器便通过判断是否有建立套接字,然后才可以选择文件,在connect函数内写上
//成功连接后,才能按选择文件
ui->buttonFile->setEnabled(true);
之后我们在serverwidget.h中定义文件,文件名,文件大小等变量,在serverwidget.cpp中引用,在选择按钮中建立槽函数。
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() << "只读方式打开文件失败 77 ";
}
ui->buttonFile->setEnabled(false);
ui->buttonSend->setEnabled(true);
}
else
{
qDebug() << "选择文件路径出错 62";
}
之后便通过发送按钮进行发送,在槽函数内我们要记住要定义文件头,防止黏包,也起到加密作用,之后再20ms后启动定时器开始发送
void ServerWidget::on_buttonSend_clicked()
{
//先发送文件头信息
QString head=QString("%1##%2").arg(fileName).arg(fileSize);
//发送头部信息
qint64 len =tcpSocket->write(head.toUtf8());
if(len>0)
{
//发送真正的文件信息
//防止TCP黏包文件
timer.start(20);
}
else
{
qDebug() << "头部信息发送失败 110";
file.close();
ui->buttonFile->setEnabled(true);
ui->buttonSend->setEnabled(false);
}
}
还有要特别注意发送必须要使用定时器,要不然发送会失败,我们在主函数connect函数下面添加定时器,还有在serverwidget.h中要定义变量QTimer timer;
connect(&timer,&QTimer::timeout,
[=]()
{
//关闭定时器
timer.stop();
//发送文件
sendData();
});
这样发送文件便完成了,紧接着我们在服务端中对发送过来的文件进行判断是否接收完成,把接收完成的信息返回给服务器,告诉它我已经接收完成。
首先,我们定义一个标志位isstart,用于判断是否可以接收,开始接收后,标志位就置false,防止再次接收。然后我们要对接收到的数据处理,判断文件头是否就是我们服务端发送的文件头,是就开始接收。
if(true==isStart)
{
//接收头
isStart=false;
//解析头部信息buf="hello##1024"
// QString str="hello##1024mike";
// 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() << "WritOnly error 40";
}
//弹出对话框,显示接收文件的大小
QString str=QString("接收的文件: [%1:%2kb]").arg(fileName).arg(fileSize);
QMessageBox::information(this,"文件信息",str);
//设置进度条
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(fileSize/1024);
ui->progressBar->setValue(0);
}
接收完后,我们在下面写一个else,判断已经接收完成,给服务器发送信息
else //文件信息
{
qint64 len =file.write(buf);
if(len>0)
{
recvSize+=len;
qDebug() <<len;
}
ui->progressBar->setValue(recvSize/1024);
if(recvSize==fileSize)
{
QString str=QString::number(recvSize);
//tcpSocket->write(str.toUtf8().data());
tcpSocket->write("file done");
file.close();
QMessageBox::information(this,"完成","文件接收完成");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
然后在服务器端写上判断是否客户端是否接收完成
connect(tcpSocket,&QTcpSocket::readyRead,
[=]()
{
QByteArray buf=tcpSocket->readAll();
if(QString(buf)=="file done")
{
//文件接收完毕
ui->textEdit->append("接收完毕");
file.close();
//断开服务端端口
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
else
{
qDebug() <<buf;
}
});
到这里就基本上完成了