通过之前三篇简书中介绍的 服务器客户端搭建 目录文件的复制 以及 变长数据包 可以完成一个简易的网盘功能。
mkPDU sendPDU revPDU 及 PDU头文件 在<C语言——变长数据包>一文中有详解
客户端上传:
upload298 getStrFromSTDIN 是一个从终端抓取字符串的函数。
301 lseek(文件描述符,偏移量,位置宏); 返回现在标记位置与文件头相差字节数
off_t lseek(int fd, off_t offset, int whence);
RETURN VALUE
Upon successful completion, lseek() returns the resulting offset loca‐
tion as measured in bytes from the beginning of the file.
通过返回值 确定文件大小 然后生成对应大小的PDU
304 g_uiId 全局变量 储存客户端id
305 getFileName 的定义
通过查找路径字符串中的最后一个 \ 找到文件名
void getFileName(char* path,char* name){
char *p1 = path;
char *p2 = NULL;
int pos = 0;
while(1){
p2 = p1;
p1 = strchr(p1+1,'/');
if(NULL == p1){
strcpy(name,p2);
return ;
}
}
}
307 copyfileToPdu // 将文件数据写入PDU
void copyfileToPdu(const char* srcPath,PDU* pdu){
int fdr = open(srcPath,O_RDONLY);
if(-1 == fdr){
printf("%s ",srcPath);
perror("read file");
}
ssize_t ret = -1;
ssize_t sended = 0;
while(1){
ret = read(fdr,(char*)(pdu->caMsg)+sended,4096);
if(-1 == ret){
if(EINTR == errno){
continue;
}
break;
}else if(0 == ret){
break;
}
sended+=ret;
}
close(fdr);
}
服务器处理上传请求:
服务器端通过 pdu 中信息 首先根据 包中的用户信息 确定该用户的网盘存储路径
之后将 pdu 中文件数据 存入该路径即可
handleUpload300 g_pUsrLink 为一条储存信息的链表
302 idToPath 将用户id转换为该用户网盘存储路径 之后和文件名拼接成最终文件存储路径
这里id 为 整数
void idToPath(uint id,char* path){
char pathT[10] = {'\0'};
int i = 0;
int j = 0;
while(1){
j = id/10;
for(int k=i;k>0;k--){
pathT[k] = pathT[k-1];
}
pathT[0] = id- j*10 + '0';
id = j;
i++;
if(id == 0){
break;
}
}
strcat(path,pathT);
}
305 copyFileFromPdu 与之前copyFileToPdu类似
从pdu中将文件拷贝至对应地址
void copyfileFromPdu(PDU* pdu,const char* desPath){
int fdw = open(desPath,O_WRONLY|O_CREAT,0777);//默认权限全打开
if(-1 == fdw){
printf("%s ",desPath);
perror("create file:");
return;
}
ssize_t ret = -1;
ssize_t left = pdu->uiMsgLen;
ssize_t writed = 0;
while(1){
if(left <= 4096){
write(fdw,pdu->caMsg+writed,left);
break;
}else{
ret = write(fdw,pdu->caMsg+writed,4096);
if(-1 == ret){
if(EINTR == errno){
continue;
}
break;
}else if(0 == ret){
break;
}
left-=ret;
writed+=ret;
}
}
close(fdw);
}
下载:
客户端向服务器发送下载请求的情况和 上传基本一致(因为懒) 这边就不重复了!
网友评论