用C++重构CloudDisk项目

20 篇文章 1 订阅

  附上项目地址CloudDisk;我已经在里面把需要的安装包都打包好了,一键安装脚本只完成了一半,慎用,不过很快就会完善它。之前是用c来完成功能的,现在想重新用C++重新架构一下,方便后续在上面增加功能。
我还是个刚入门萌新,分享的一些东西并不一定准确,还望大佬们多多指教。

一、代码架构

二、代码解析

  代码文件github上面有,就不详细列出来了,简单说一下业务逻辑。
  file.h头文件,主要作为文件属性类,其中包含文件上传操作时所需要获取的所有文件属性,方便后续各种操作。upload.h继承file.h,其中封装了fastCGI的接收文件函数FCGI_Accept();然后定义了解析数据函数ParseDataAndSave(),实现对通过cgi传输的数据的解析功能。其中通过对数据的截取,得到了文件名,并且通过memcmp()函数拷贝了一份文件,这份拷贝的文件就是后面写入fastDFS的文件。UploadFile()函数实现了对fastDFS文件上传流程的封装,具体代码我贴在下面:

bool Upload::UploadFile(char *fileName) {
	if (!fastDFS.FdfsClientInit()) {
		cout << "fastdfs initial failed." << endl;
		return false;
	}

	if (!fastDFS.TrackerGetConnection()) {
		cout << "tracker initial failed." << endl;
		fastDFS.FdfsClientDestroy();
		return false;
	}

	if (!fastDFS.TrackerQueryStorageStore()) {
		cout << "storage initial failed." << endl;
		fastDFS.FdfsClientDestroy();
		return false;
	}

	if (!fastDFS.StorageUploadByFilename1(fileName, fileId)) {
		cout << "StorageUploadByFilename1 initial failed." << endl;
		fastDFS.FdfsClientDestroy();
		return false;
	}

	if (!fastDFS.TrackerCloseConnectionEx()) {
		cout << "TrackerCloseConnectionEx initial failed." << endl;
		fastDFS.FdfsClientDestroy();
		return false;
	}

	fastDFS.FdfsClientDestroy();
	printf("<br>fileid: %s\n<br>", fileId);
	
	return true;
}

  具体的实现流程封装在FastDFS这个类里,到时候可以具体介绍。
  随后是SaveToMysql()这个函数,它实现了将filename和传入fastDFS得到的fileid存入数据库功能,详细步骤就是拼装sql语句,调用mysql接口进行写入。
  讲一下比较重要的两个函数:

bool Upload::AcceptFile() {
	while (fastCGI.FcgiAccept()) {
		
		fastCGI.contentLen = getenv("CONTENT_LENGTH");
		printf("Content-type: text/html\r\n\r\n");
		
		if (fastCGI.contentLen != NULL) {
			buflen = strtol(fastCGI.contentLen, nullptr, 10);
		}

		if (buflen <= 0) {
			LOG("No data from standard input.");
		}
		else {
			char tmpch;
			
			fileData = (char*)malloc(buflen);
			pbegin = ptemp = fileData;
			
			for (int i = 0; i < buflen; ++i) {
				if ((tmpch = getchar()) < 0) {
					LOG("receive filedata successful.");
					break;
				}
				*ptemp = tmpch;
				++ptemp;
			}

			pend = ptemp;
		}

		ParseDataAndSave();
		UploadFile(fileName);
		SaveToMysql();
		free(fileData);
		unlink(fileName);
	}

	return true;
}

  这是数据接收函数,通过指针一个字符一个字符的接数据流,得到filedata。其数据流的大小是通过环境变量CONTENT_LENGTH得到的,而后会通过ParseDataAndSave()对数据流进一步解析:

bool Upload::ParseDataAndSave() {
	ptemp = strstr(pbegin, "\r\n");
	strncpy(fastCGI.boundary, pbegin, ptemp - pbegin);

	ptemp += 2;
	buflen -= (ptemp - pbegin);
	pbegin = ptemp;
	char* pfileNameBegin = strstr(pbegin, "filename=");
	pfileNameBegin += strlen("filename=");  
	char* pfileNameEnd = strchr(++pfileNameBegin, '"');  
	strncpy(fileName, pfileNameBegin, pfileNameEnd - pfileNameBegin);
	printf("<br>filename: %s<br>\n", fileName);

	ptemp = strstr(pbegin, "\r\n");
	ptemp += 2;
	buflen -= (ptemp - pbegin);  
	pbegin = ptemp;
	ptemp = strstr(pbegin, "\r\n");
	ptemp += 4;
	buflen -= (ptemp - pbegin);  


	pbegin = ptemp;

	int boderLen = strlen(fastCGI.boundary);
	int FullDataLen = buflen - boderLen + 1;
	for (int i = 0; i < FullDataLen; ++i) {
		if (*pbegin == *fastCGI.boundary) {
			if (memcmp(pbegin, fastCGI.boundary, boderLen) == 0) {
				break;
			}
		}
		++pbegin;
	}
	swap(pbegin, ptemp);
	if (ptemp == nullptr) {
		ptemp = pend;
	}

	ptemp -= 2;  


	int fd = open(fileName, O_CREAT | O_WRONLY, 0664);
	write(fd, pbegin, ptemp - pbegin);
	close(fd);

	return true;
}

  该函数用指针对数据流进行了切割,因为通过CGI接收的数据是有固定格式的,所以通过其固定格式来定位切割,从而得到filename和得到文件真实的数据块,并通过文件描述符将其写成文件。
  完成这些工作之后,后面几乎就是走流程了,将得到的文件传给fastDFS做处理就行了,然后将得到的filenam和fastDFS返回的fileid存入数据库,fileid就是该文件在fastDFS系统中的访问路径,通过web页面可以直接访问的。基本的文件上传流程就是如此了,功能还是比较简单的,后续还会把该系统功能丰富起来,比如加上后台log监控,加上必要的文件下载浏览等功能,emmm,任重而道远。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值