因为是我刚接触qt不久学习的过程,所以有对实现功能的前提基础有一些介绍。我介绍的是一个实现过程,有核心的实现代码,在我测试后发现在局域网内传输速度大于200m/s时发送较大文件可能会稍有卡顿,不过等一会儿发送完毕后就正常了,如果在公网上传输则取决于你的传输速度。
首先要建立一个tcp的连接。
fileSocket->abort();
fileSocket->connectToHost(IP, 8888);
if(!fileSocket->waitForConnected(1000))
{
qDebug() << "fileSocket Connection failed!"<<"error"<<fileSocket->error();
this->close();
return;
}
qDebug() << "fileSocket Connect successfully!";
这个是客户端片段,比较简单,相关博客非常多,客户端发起连接请求后,服务端监听这个端口就好了,这个IP则是服务端的ip地址。
TcpServer ser; //这个是我重写的类 qt原始的类是QTcpServer
ser.listen(QHostAddress::Any,8888);
一、服务端部分:
服务端部分我重写了QTcpSocket类目的是为了多客户端连接,这个先不说
这是服务端部分发送和接收的槽函数和一些参数初始化,(readyRead()信号需要注意的是并不是客户端write一次就会触发一次)
connect(this, SIGNAL(readyRead()), this, SLOT(updateFileProgress()));
//接受文件的槽函数
connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(updateFileProgress(qint64)));
//发送文件的槽函数
bytesWritten = 0; //已发送的文件字节数大小用来判断是否发送完毕
perDataSize = 64 * 1024; //每次发送的最大字节数
bytesReceived = 0; //已接收的文件字节数大小
totalBytes = 0; //文件名和文件实际内容的总大小
filenameSize = 0; //文件名大小
接收槽函数(updateFileProgress()//receive)具体实现
QString ip,ordertype;
QDataStream inFile(this);
inFile.setVersion(QDataStream::Qt_4_8);
if (bytesReceived <= sizeof(qint64)* 2)
{
if ((this->bytesAvailable() >= (sizeof(qint64)) * 2) && (filenameSize == 0))
//首次接收文件总大小和文件名大小
{
inFile >> totalBytes >> filenameSize;
bytesReceived += sizeof(qint64)* 2;
}
if ((this->bytesAvailable() >= filenameSize) && (filenameSize != 0))
{
//这里接收文件名和发送方ip相关信息的部分 如果
inFile >> filename>>ip;
bytesReceived += filenameSize;
if(filename=="*****")
{
//这里可以对文件名进行判断 然后选择相应的文件保存目录也可以利用getSaveFileName手动选取目录
}
localFile = new QFile(filename);
if (!localFile->open(QFile::WriteOnly))
{
qDebug() << "Server::open file error!";
return;
}
}
else
{
QString other=this->readAll();
//这里可以根据接收内容执行不是文件传输时需要执行的操作
}
}
if (bytesReceived < totalBytes) //文件未传输完毕时持续接收剩余要接收的内容
{
bytesReceived += this->bytesAvailable();
inBlock = this->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
//qDebug()<<totalBytes;
//qDebug()<<bytesReceived;
if (bytesReceived == totalBytes)//内容发送完毕后释放文件
{
qDebug()<<"Receive file successfully!";
bytesReceived = 0;
totalBytes = 0;
filenameSize = 0;
localFile->close();
//filesocket->close();
}
发送部分与接收部分是对应的,分两部分,一个是首次发送部分,和后续文件实际内容发送部分,首次发送部分包括发送方ip,文件名,文件总大小
首次发送函数具体实现
QString ip;
QList<QHostAddress> NetList = QNetworkInterface::allAddresses(); //取得ip等全部信息
for(int i=0;i<NetList.count();i++)
{
ip.append(NetList.at(i).toString());
}
this->localFile = new QFile(filename); //这个filname是发送目标文件的目录
if (!localFile->open(QFile::ReadOnly))
{
return;
}
this->totalBytes = localFile->size();
QDataStream sendout(&outBlock, QIODevice::WriteOnly);//用QDataStream类做缓冲区
sendout.setVersion(QDataStream::Qt_4_8);
QString FileName = filename.right(filename.size() - filename.lastIndexOf('/') - 1);
//文件名
sendout << qint64(0) << qint64(0) << FileName;
sendout<<ip;
totalBytes += outBlock.size();
sendout.device()->seek(0);
sendout << totalBytes << qint64((outBlock.size() - sizeof(qint64)* 2));
bytestoWrite = totalBytes - this->write(outBlock);
outBlock.resize(0);
接着是后续发送槽函数(updateFileProgress(qint64 numBytes))具体实现
bytesWritten += (int)numBytes;
if (bytestoWrite > 0)
{
outBlock = localFile->read(qMin(bytestoWrite, perDataSize));
bytestoWrite -= ((int)fileSocket->write(outBlock));
outBlock.resize(0);
}
else
{
localFile->close(); //发生某些错误直接结束
}
//progressBar->setMaximum(totalBytes);//这里可以用来显示已经发送的大小
//progressBar->setValue(bytesWritten);
if (bytesWritten == totalBytes) //发送完毕
{
bytesWritten = 0;
localFile->close();
//fileSocket->close();
}
二、客户端部分
客户端部分文件传输的部分跟服务端是一样的,从文件传输的角度来看不分服务和客户端,原来的完整代码已经没有了,现在是临时写出来的。谢谢大家~
|