各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中的文件列表,还有删除用户在服务器中的文件,最后的可以共享文件给好友。
列出用户在服务器中的文件列表
增加一个结构体
1 struct FileList 2 { 3 int cnt; 4 char list[16][128]; 5 };
为了方便我就假设服务器最多可以存16个单个用户的文件。如果想要支持更多的文件,这里可以增加一个int pages;用于分页作用,我们在服务器中获取文件时,可以根据分页进行发送。这样既方便又能支持多文件。
client.cpp这个客户端文件增加一个函数
1 int file_list(struct Addr addr,struct User user) 2 { 3 struct sockaddr_in servAddr; 4 struct hostent *host; 5 struct Control control; 6 struct FileList filelist; 7 int sockfd; 8 9 host=gethostbyname(addr.host); 10 servAddr.sin_family=AF_INET; 11 servAddr.sin_addr=*((struct in_addr *)host->h_addr); 12 servAddr.sin_port=htons(addr.port); 13 if(host==NULL) 14 { 15 perror("获取IP地址失败"); 16 exit(-1); 17 } 18 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 19 { 20 perror("socket创建失败"); 21 exit(-1); 22 } 23 if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-1) 24 { 25 perror("connect 失败"); 26 exit(-1); 27 } 28 29 //控制信号 30 control.control=FILE_LIST; 31 control.uid=user.uid; 32 if(send(sockfd,(char *)&control,sizeof(struct Control),0)<0) 33 { 34 perror("文件指纹发送失败"); 35 exit(-1); 36 } 37 if(recv(sockfd,(char *)&filelist,sizeof(struct FileList),0)<0) 38 { 39 perror("获取文件列表失败"); 40 exit(-1); 41 } 42 for(int i=0;i<filelist.cnt;i++) 43 { 44 printf("--> %s\n",filelist.list[i]); 45 } 46 47 close(sockfd); 48 return 0; 49 }
然后在主函数中调用即可。
server.cpp实现,在主函数的case FILE_LIST:处修改如下
1 case FILE_LIST: 2 { 3 struct File file; 4 struct FileList filelist; 5 file.uid=control.uid; 6 mysql_get_file_list(file,&filelist); 7 send(clientfd,(char *)&filelist,sizeof(struct FileList),0); 8 break; 9 }
然后再增加一个对应的mysql_get_file_list函数
1 int mysql_get_file_list(struct File file,struct FileList *filelist) 2 { 3 MYSQL conn; 4 MYSQL_RES * res_ptr; 5 MYSQL_ROW result_row; 6 int res;int row;int column; 7 int i,j; 8 char sql[256]={0}; 9 char ch[64]; 10 //select filename from files,relations where relations.uid=[file].uid and relations.fid=files.fid; 11 strcpy(sql,"select filename from files,relations where relations.uid="); 12 sprintf(ch,"%d",file.uid); 13 strcat(sql,ch); 14 strcat(sql," and relations.fid=files.fid ;"); 15 //printf("==>%s\n",sql); 16 17 mysql_init(&conn); 18 if(mysql_real_connect(&conn,"localhost","root","","filetranslate",0,NULL,CLIENT_FOUND_ROWS)) 19 { 20 res=mysql_query(&conn,sql); 21 if(res) 22 { 23 perror("select sql error1"); 24 } 25 else 26 { 27 res_ptr=mysql_store_result(&conn); 28 if(res_ptr) 29 { 30 column=mysql_num_fields(res_ptr); 31 row=mysql_num_rows(res_ptr)+1; 32 //按行输出结果 33 filelist->cnt=row-1; 34 for(i=1;i<row;i++) 35 { 36 result_row=mysql_fetch_row(res_ptr); 37 strcpy(filelist->list[i-1],result_row[0]); 38 //printf("%s",result_row[0]); 39 } 40 } 41 else 42 { 43 printf("没有数据\n"); 44 } 45 } 46 } 47 else 48 { 49 perror("Connect Failed1\n"); 50 exit(-1); 51 } 52 mysql_close(&conn); 53 return 0; 54 }
运行时的截图
删除服务器中的用户文件
在client.cpp中增加一个file_delete函数
1 int file_delect(struct Addr addr,struct User user,char *filenames) 2 { 3 struct sockaddr_in servAddr; 4 struct hostent *host; 5 struct Control control; 6 struct File file; 7 int sockfd; 8 9 host=gethostbyname(addr.host); 10 servAddr.sin_family=AF_INET; 11 servAddr.sin_addr=*((struct in_addr *)host->h_addr); 12 servAddr.sin_port=htons(addr.port); 13 if(host==NULL) 14 { 15 perror("获取IP地址失败"); 16 exit(-1); 17 } 18 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 19 { 20 perror("socket创建失败"); 21 exit(-1); 22 } 23 if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-1) 24 { 25 perror("connect 失败"); 26 exit(-1); 27 } 28 29 //控制信号 30 control.control=FILE_DELECT; 31 control.uid=user.uid; 32 if(send(sockfd,(char *)&control,sizeof(struct Control),0)<0) 33 { 34 perror("文件指纹发送失败"); 35 exit(-1); 36 } 37 file.uid=user.uid; 38 strcpy(file.filename,filenames); 39 if(send(sockfd,(char *)&file,sizeof(struct File),0)<0) 40 { 41 perror("删除文件失败"); 42 exit(-1); 43 } 44 char ch[32]; 45 memset(ch,0,sizeof(ch)); 46 if(recv(sockfd,ch,sizeof(ch),0)<0) 47 { 48 perror("删除文件失败"); 49 exit(-1); 50 } 51 if(ch[0]=='y') //删除成功 52 { 53 printf("删除成功\n");; 54 } 55 else if(ch[0]=='n') //删除失败 56 { 57 printf("删除失败,确认是否有该文件\n");; 58 } 59 close(sockfd); 60 return 0; 61 }
在server.cpp的main函数中增加
1 case FILE_DELECT: 2 { 3 struct File file; 4 char ch[64]; 5 memset(ch,0,sizeof(ch)); 6 recv(clientfd,(char *)&file,sizeof(struct File),0); 7 int t=mysql_delete_file(file); 8 if(t==-1) 9 { 10 printf("没有对应的文件\n");; 11 strcpy(ch,"no"); 12 send(clientfd,ch,64,0); 13 break; 14 } 15 strcpy(ch,"yes"); 16 send(clientfd,ch,64,0); 17 printf("删除成功\n"); 18 break; 19 }
然后在server.cpp中再增加一个mysql_delete_file函数
1 int mysql_delete_file(struct File file) 2 { 3 MYSQL conn; 4 MYSQL_RES * res_ptr; 5 MYSQL_ROW result_row; 6 int res;int row;int column; 7 int i,j; 8 char sql[256]; 9 char ch[64]; 10 int fid;int rt=0; 11 12 mysql_init(&conn); 13 if(mysql_real_connect(&conn,"localhost","root","","filetranslate",0,NULL,CLIENT_FOUND_ROWS)) 14 { 15 //select files.fid from files,relations where relations.fid=files.fid and filename= [file].filename 16 strcpy(sql,"select files.fid from files,relations where relations.fid=files.fid and filename=\""); 17 strcat(sql,file.filename); 18 strcat(sql,"\";"); 19 res=mysql_query(&conn,sql); 20 fid=0; 21 if(res) 22 { 23 perror("Select Sql Error!"); 24 } 25 else 26 { 27 res_ptr=mysql_store_result(&conn); 28 if(res_ptr) 29 { 30 column=mysql_num_fields(res_ptr); 31 row=mysql_num_rows(res_ptr)+1; 32 if(row<=1) 33 ; 34 else 35 { 36 result_row=mysql_fetch_row(res_ptr); 37 if(result_row[0]==NULL) 38 { 39 fid=0; 40 } 41 else 42 { 43 fid=atoi(result_row[0]); 44 } 45 } 46 } 47 else 48 { 49 fid=0; 50 } 51 } 52 if(fid==0) 53 { 54 mysql_close(&conn); 55 return -1; 56 } 57 //根据获取到的fid然后删除relations对应fid和uid 58 //delect relations where uid='uid' and fid='fid' 59 strcpy(sql,"delete from relations where uid="); 60 sprintf(ch,"%d",file.uid); 61 strcat(sql,ch); 62 strcat(sql," and fid="); 63 sprintf(ch,"%d",fid); 64 strcat(sql,ch); 65 res=mysql_query(&conn,sql); 66 if(res) 67 { 68 printf("Delete Error\n"); 69 } 70 else 71 { 72 ;; 73 } 74 } 75 else 76 { 77 perror("Connect Failed!"); 78 exit(-1); 79 } 80 81 mysql_close(&conn); 82 return rt; 83 }
从上面的sql语句可以知道我们只是删除了relations表中的链接而已。而没有真正的删除已经上传上去的文件。这一点可以参考以前给过的资料。
运行的截图如下
文件共享给好友
client.cpp文件加入一个函数
1 int file_sendto(struct Addr addr,struct User user,char *filenames,struct User to) 2 { 3 struct sockaddr_in servAddr; 4 struct hostent *host; 5 struct Control control; 6 struct File file; 7 int sockfd; 8 9 host=gethostbyname(addr.host); 10 servAddr.sin_family=AF_INET; 11 servAddr.sin_addr=*((struct in_addr *)host->h_addr); 12 servAddr.sin_port=htons(addr.port); 13 if(host==NULL) 14 { 15 perror("获取IP地址失败"); 16 exit(-1); 17 } 18 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 19 { 20 perror("socket创建失败"); 21 exit(-1); 22 } 23 if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-1) 24 { 25 perror("connect 失败"); 26 exit(-1); 27 } 28 29 //控制信号 30 control.control=FILE_SENDTO; 31 control.uid=user.uid; 32 if(send(sockfd,(char *)&control,sizeof(struct Control),0)<0) 33 { 34 perror("文件指纹发送失败"); 35 exit(-1); 36 } 37 file.uid=user.uid; 38 strcpy(file.filename,filenames); 39 if(send(sockfd,(char *)&file,sizeof(struct File),0)<0) 40 { 41 perror("共享文件失败"); 42 exit(-1); 43 } 44 if(send(sockfd,(char *)&to,sizeof(struct User),0)<0) 45 { 46 perror("共享用户发送失败"); 47 exit(-1); 48 } 49 char ch[32]; 50 memset(ch,0,sizeof(ch)); 51 if(recv(sockfd,ch,sizeof(ch),0)<0) 52 { 53 perror("共享文件失败"); 54 exit(-1); 55 } 56 if(ch[0]=='y') //删除成功 57 { 58 printf("共享成功\n");; 59 } 60 else if(ch[0]=='n') //删除失败 61 { 62 if(ch[2]=='1') 63 printf("共享失败,确认是否有该文件\n"); 64 else if(ch[2]=='2') 65 printf("共享失败,确认是否有该用户\n"); 66 } 67 close(sockfd); 68 return 0; 69 }
而server.cpp在主函数main中switch中增加如下
1 case FILE_SENDTO: 2 { 3 struct File file; 4 struct User to; 5 recv(clientfd,(char *)&file,sizeof(struct File),0); 6 recv(clientfd,(char *)&to,sizeof(struct User),0); 7 int t=mysql_sendto(file,to); 8 char ch[64]; 9 memset(ch,0,sizeof(ch)); 10 if(t==-1) 11 { 12 printf("没有对应的文件\n");; 13 strcpy(ch,"no1"); 14 send(clientfd,ch,64,0); 15 break; 16 } 17 else if(t==-2) 18 { 19 printf("没有对应的用户\n");; 20 strcpy(ch,"no2"); 21 send(clientfd,ch,64,0); 22 break; 23 } 24 strcpy(ch,"yes"); 25 send(clientfd,ch,64,0); 26 printf("共享成功\n"); 27 break; 28 }
然后对应的增加下面一个函数
1 int mysql_sendto(struct File file,struct User to) 2 { 3 //insert into relations values(uid,fid); 4 MYSQL conn; 5 MYSQL_RES * res_ptr; 6 MYSQL_ROW result_row; 7 int res;int row;int column; 8 int i,j;int fid;int uid;int rt=0; 9 char sql[256]; 10 char ch[64]; 11 12 mysql_init(&conn); 13 if(mysql_real_connect(&conn,"localhost","root","","filetranslate",0,NULL,CLIENT_FOUND_ROWS)) 14 { 15 //select files.fid from files,relations where relations.fid=files.fid and filename=files.filename; 16 //得到fid后 17 strcpy(sql,"select files.fid from files,relations where relations.fid=files.fid and filename=\""); 18 strcat(sql,file.filename); 19 strcat(sql,"\";"); 20 res=mysql_query(&conn,sql); 21 fid=0; 22 if(res) 23 { 24 perror("Select Sql Error!"); 25 } 26 else 27 { 28 res_ptr=mysql_store_result(&conn); 29 if(res_ptr) 30 { 31 column=mysql_num_fields(res_ptr); 32 row=mysql_num_rows(res_ptr)+1; 33 if(row<=1) 34 ; 35 else 36 { 37 result_row=mysql_fetch_row(res_ptr); 38 if(result_row[0]==NULL) 39 { 40 fid=0; 41 } 42 else 43 { 44 fid=atoi(result_row[0]); 45 } 46 } 47 } 48 else 49 { 50 fid=0; 51 } 52 } 53 if(fid==0) 54 { 55 mysql_close(&conn); 56 return -1;//表示没有该文件 57 } 58 59 //select uid from users where username=[to].username; 60 //得到uid后 61 strcpy(sql,"select uid from users where username=\""); 62 strcat(sql,to.username); 63 strcat(sql,"\""); 64 res=mysql_query(&conn,sql); 65 uid=0; 66 if(res) 67 { 68 perror("Select Sql Error!"); 69 } 70 else 71 { 72 res_ptr=mysql_store_result(&conn); 73 if(res_ptr) 74 { 75 column=mysql_num_fields(res_ptr); 76 row=mysql_num_rows(res_ptr)+1; 77 if(row<=1) 78 ; 79 else 80 { 81 result_row=mysql_fetch_row(res_ptr); 82 if(result_row[0]==NULL) 83 { 84 uid=0; 85 } 86 else 87 { 88 uid=atoi(result_row[0]); 89 } 90 } 91 } 92 else 93 { 94 uid=0; 95 } 96 } 97 if(uid==0) 98 { 99 mysql_close(&conn); 100 return -2;//表示没有该用户 101 } 102 103 //将获取到的uid fid插入到数据库relations中 104 //insert into relations values(uid,fid); 105 strcpy(sql,"insert into relations values( "); 106 sprintf(ch,"%d",uid); 107 strcat(sql,ch); 108 strcat(sql,", "); 109 sprintf(ch,"%d",fid); 110 strcat(sql,ch); 111 strcat(sql,");"); 112 res=mysql_query(&conn,sql); 113 printf("==========> uid=%d fid=%d\n",uid,fid); 114 if(res) 115 { 116 rt=-1; 117 printf("Insert Error\n"); 118 } 119 else 120 { 121 printf("Insert Success\n"); 122 } 123 } 124 else 125 { 126 perror("Connect Failed!"); 127 exit(-1); 128 } 129 mysql_close(&conn); 130 return rt; 131 }
下面这个是运行时的截图
在本次程序的最后,送上程序代码结构,及本人的开发环境。
从程序中可以看出很多代码是有冗余的,如果进行重构的话,估计代码可以节省50%。可怕的新手啊(◑﹏◐)。从代码量上看,这次的代码量也不少了,相比与上次聊天程序,代码量有过之而不及,不过可喜的是这次都把具体的功能封装成一个一个的函数,即使有冗余代码。不过还是有点小进步了。
Socket网络编程--小小网盘程序各个小节的传送门
Socket网络编程--小小网盘程序(1) http://www.cnblogs.com/wunaozai/p/3886588.html
Socket网络编程--小小网盘程序(2) http://www.cnblogs.com/wunaozai/p/3887728.html
Socket网络编程--小小网盘程序(3) http://www.cnblogs.com/wunaozai/p/3891062.html
Socket网络编程--小小网盘程序(4) http://www.cnblogs.com/wunaozai/p/3892729.html
Socket网络编程--小小网盘程序(5) http://www.cnblogs.com/wunaozai/p/3893469.html