qt实现基于FTP文件存储系统实现多线程上传,多文件下载
github:https://github.com/xiaofengyun/FTP-FILE-transporthttps://github.com/xiaofengyun/FTP-FILE-transport.git无线网络下基于FTP文件存储系统运行环境如下:开发平台:Windows 10(客户端),Linux(服务端)开发环境:Qt Creator,Ce...
github:https://github.com/xiaofengyun/FTP-FILE-transport
https://github.com/xiaofengyun/FTP-FILE-transport.git
无线网络下基于FTP文件存储系统运行环境如下:
开发平台:Windows 10(客户端),Linux(服务端)
开发环境:Qt Creator,Centos 7
编译环境:G++,GDB,qmake
运行环境:Qt 5.5.1,Centos 7
多线程上传的逻辑:
选择完一个文件后,通过偏移文件指针lseek()得到文件的size。接下来将大文件按照一定的方法拆分,首先,先比较文件的大小与切片大小,切片大小是一个定值。如果文件的大小小于切片的大小,那么不必进行多线程上传,单线程就可以了。当需要多线程上传的时候,首先计算出线程个数,通过用size/切片大小和size%切片大小的方式计算出需要的线程数。接下来便是传输文件,使用read()函数按字节去读取文件,每次读取一定的字节数到一个缓冲区。然后便是加标志位。犹豫线程是并发执行的,无法预测哪一个线程会首先完成传输,这会对文件的合并差生巨大的影响,所以必须加上标志位,判断数据片段是属于哪一个位置的。在缓冲区的前两个字节加上线程ID作为标志位,然后将读取的文件数据凭借到缓冲区后面,这样便组成了一个数据包,每个线程将这个数据包发送给服务端,然后自行关闭。
客户端多线程上传程序:
void MainWindow::thread_upload()/多线程上传
{
qDebug() << "start thread upload...";
qint64 m_totalBytes;
QFile * m_localFile;
QString path = QFileDialog::getOpenFileName(this, "Open a file", "/", "files (*)");
QFileInfo info(path);//path就是打开文件的路径
m_localFile = new QFile(path);//类似一个文件指针
if (!m_localFile->open(QFile::ReadOnly))
{
qDebug() << "open file error!";
return;
}
//打开成功
qDebug() << "打开文件成功!";
m_totalBytes = m_localFile->size();//得到文件总大小
QString size = QString::number(m_totalBytes, 10);
qDebug() << "文件大小:" << m_localFile->size();
QString up = "upload";
up += " " + info.fileName() + " " + size;
char* ch;
QByteArray ba = up.toLatin1(); // must
ch = ba.data();
sockfd->write(ch);///向服务端发送上传请求,等待回应
if (sockfd->waitForReadyRead(10))
{
QByteArray buff = sockfd->readAll();//接收服务端返回的消息
qDebug() << buff;
if (strncmp(buff, "ok", 2) != 0)
{
qDebug() << "server no message...";
return;
}
int n = 0;
int i = 0;
threadDown *thread[SIZE];
char sendbuff[1024] = { 0 };
size_int = size.toInt();
qDebug() << "size=" << size_int;
int num_thread = size_int / 1000;1000为分片大小,大小自己定义
if (size_int - num_thread * 1000>0)
{
num_thread++;///需要开启的线程数,也就是分片的个数
}
qDebug() << "thread=" << num_thread;
for (; i<num_thread; i++)
{
qDebug() << "i=" << i;
if (i <= 9)
{
sprintf(sendbuff, "%d", i);
sprintf(sendbuff + 1, "%s", NULL);
}
else
{
sprintf(sendbuff, "%d", i);
}
n = m_localFile->read(sendbuff + 2, 1000);每个数据包的前两个字节表示线程id,也就是标识符
thread[i] = new threadDown(sendbuff, i); //新建线程对象,在线程中将数据发送就可以了
thread[i]->start(); //启动线程
bool b = connect(thread[i], SIGNAL(thread_to_main(char *, int)), this, SLOT(start_to_up(char *, int)));
qDebug() << "b=" << b;
thread[i]->wait();
memset(sendbuff, 0, sizeof(sendbuff));
qDebug() << "------------------------------------------------------------";
}
}
//多线程上传时,服务端接收处理程序
while ((num = recv(c, buff, 1002, 0))>0)
{
printf("num =%d\n", num);
printf("%s\n", buff);
char seq[2] = "";
seq[0] = buff[0];
seq[1] = buff[1];
//cout<<"seq="<<seq;
printf("seq=%s\n", seq);
int pro_seq = atoi(seq);//求出线程数
printf("id =%d\n", pro_seq);
cout++;
num -= 2;
printf("%s\n", buff);
printf("len=%d\n", strlen(buff));
cur_size += num;
printf("cur_size=%d\n", cur_size);
printf("线程id=%d\n", pro_seq);
int off = lseek(fd, pro_seq * 1000, SEEK_SET);//偏移到原本数据分片的地方
printf("偏移字节=%d\n", off);
write(fd, buff + 2, strlen(buff) - 2);
memset(buff, 0, sizeof(buff));
lseek(fd, 0, SEEK_SET);//指针重置
printf("-----------------------------------=--------------\n");
printf("cur_size=%d\n", cur_size);
if (cur_size >= size)
{
break;
}
}
多文件下载:
为了实现多文件同时下载,采用了多客户端程序连接服务端的方式。前面提到过,服务端可以承受多客户端的连接,所以当有多个文件去下载时,表面上是由一个用户发出的请求,在内部实现时,模拟多用户去下载的过程。
步骤:
1.开启多个线程,将要下载的文件名传入各个线程;
2.再线程函数中创建套接字去下载文件即可。
运行截图:
代码在git里面,需要借鉴的可以看。代码完全是本人自己的想法,如有不对或者错误请指正,交流加QQ:965829642.
更多推荐
所有评论(0)