各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中的文件列表,还有删除用户在服务器中的文件,最后的可以共享文件给好友。

  列出用户在服务器中的文件列表

  增加一个结构体

 struct FileList
{
int cnt;
char list[][];
};

  为了方便我就假设服务器最多可以存16个单个用户的文件。如果想要支持更多的文件,这里可以增加一个int pages;用于分页作用,我们在服务器中获取文件时,可以根据分页进行发送。这样既方便又能支持多文件。

  client.cpp这个客户端文件增加一个函数

 int file_list(struct Addr addr,struct User user)
{
struct sockaddr_in servAddr;
struct hostent *host;
struct Control control;
struct FileList filelist;
int sockfd; host=gethostbyname(addr.host);
servAddr.sin_family=AF_INET;
servAddr.sin_addr=*((struct in_addr *)host->h_addr);
servAddr.sin_port=htons(addr.port);
if(host==NULL)
{
perror("获取IP地址失败");
exit(-);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-)
{
perror("socket创建失败");
exit(-);
}
if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-)
{
perror("connect 失败");
exit(-);
} //控制信号
control.control=FILE_LIST;
control.uid=user.uid;
if(send(sockfd,(char *)&control,sizeof(struct Control),)<)
{
perror("文件指纹发送失败");
exit(-);
}
if(recv(sockfd,(char *)&filelist,sizeof(struct FileList),)<)
{
perror("获取文件列表失败");
exit(-);
}
for(int i=;i<filelist.cnt;i++)
{
printf("--> %s\n",filelist.list[i]);
} close(sockfd);
return ;
}

  然后在主函数中调用即可。

  server.cpp实现,在主函数的case FILE_LIST:处修改如下

  case FILE_LIST:
{
struct File file;
struct FileList filelist;
file.uid=control.uid;
mysql_get_file_list(file,&filelist);
send(clientfd,(char *)&filelist,sizeof(struct FileList),);
break;
}

  然后再增加一个对应的mysql_get_file_list函数

 int mysql_get_file_list(struct File file,struct FileList *filelist)
{
MYSQL conn;
MYSQL_RES * res_ptr;
MYSQL_ROW result_row;
int res;int row;int column;
int i,j;
char sql[]={};
char ch[];
//select filename from files,relations where relations.uid=[file].uid and relations.fid=files.fid;
strcpy(sql,"select filename from files,relations where relations.uid=");
sprintf(ch,"%d",file.uid);
strcat(sql,ch);
strcat(sql," and relations.fid=files.fid ;");
//printf("==>%s\n",sql); mysql_init(&conn);
if(mysql_real_connect(&conn,"localhost","root","","filetranslate",,NULL,CLIENT_FOUND_ROWS))
{
res=mysql_query(&conn,sql);
if(res)
{
perror("select sql error1");
}
else
{
res_ptr=mysql_store_result(&conn);
if(res_ptr)
{
column=mysql_num_fields(res_ptr);
row=mysql_num_rows(res_ptr)+;
//按行输出结果
filelist->cnt=row-;
for(i=;i<row;i++)
{
result_row=mysql_fetch_row(res_ptr);
strcpy(filelist->list[i-],result_row[]);
//printf("%s",result_row[0]);
}
}
else
{
printf("没有数据\n");
}
}
}
else
{
perror("Connect Failed1\n");
exit(-);
}
mysql_close(&conn);
return ;
}

  运行时的截图

  删除服务器中的用户文件

  在client.cpp中增加一个file_delete函数

 int file_delect(struct Addr addr,struct User user,char *filenames)
{
struct sockaddr_in servAddr;
struct hostent *host;
struct Control control;
struct File file;
int sockfd; host=gethostbyname(addr.host);
servAddr.sin_family=AF_INET;
servAddr.sin_addr=*((struct in_addr *)host->h_addr);
servAddr.sin_port=htons(addr.port);
if(host==NULL)
{
perror("获取IP地址失败");
exit(-);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-)
{
perror("socket创建失败");
exit(-);
}
if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-)
{
perror("connect 失败");
exit(-);
} //控制信号
control.control=FILE_DELECT;
control.uid=user.uid;
if(send(sockfd,(char *)&control,sizeof(struct Control),)<)
{
perror("文件指纹发送失败");
exit(-);
}
file.uid=user.uid;
strcpy(file.filename,filenames);
if(send(sockfd,(char *)&file,sizeof(struct File),)<)
{
perror("删除文件失败");
exit(-);
}
char ch[];
memset(ch,,sizeof(ch));
if(recv(sockfd,ch,sizeof(ch),)<)
{
perror("删除文件失败");
exit(-);
}
if(ch[]=='y') //删除成功
{
printf("删除成功\n");;
}
else if(ch[]=='n') //删除失败
{
printf("删除失败,确认是否有该文件\n");;
}
close(sockfd);
return ;
}

  在server.cpp的main函数中增加

 case FILE_DELECT:
{
struct File file;
char ch[];
memset(ch,,sizeof(ch));
recv(clientfd,(char *)&file,sizeof(struct File),);
int t=mysql_delete_file(file);
if(t==-)
{
printf("没有对应的文件\n");;
strcpy(ch,"no");
send(clientfd,ch,,);
break;
}
strcpy(ch,"yes");
send(clientfd,ch,,);
printf("删除成功\n");
break;
}

  然后在server.cpp中再增加一个mysql_delete_file函数

 int mysql_delete_file(struct File file)
{
MYSQL conn;
MYSQL_RES * res_ptr;
MYSQL_ROW result_row;
int res;int row;int column;
int i,j;
char sql[];
char ch[];
int fid;int rt=; mysql_init(&conn);
if(mysql_real_connect(&conn,"localhost","root","","filetranslate",,NULL,CLIENT_FOUND_ROWS))
{
//select files.fid from files,relations where relations.fid=files.fid and filename= [file].filename
strcpy(sql,"select files.fid from files,relations where relations.fid=files.fid and filename=\"");
strcat(sql,file.filename);
strcat(sql,"\";");
res=mysql_query(&conn,sql);
fid=;
if(res)
{
perror("Select Sql Error!");
}
else
{
res_ptr=mysql_store_result(&conn);
if(res_ptr)
{
column=mysql_num_fields(res_ptr);
row=mysql_num_rows(res_ptr)+;
if(row<=)
;
else
{
result_row=mysql_fetch_row(res_ptr);
if(result_row[]==NULL)
{
fid=;
}
else
{
fid=atoi(result_row[]);
}
}
}
else
{
fid=;
}
}
if(fid==)
{
mysql_close(&conn);
return -;
}
//根据获取到的fid然后删除relations对应fid和uid
//delect relations where uid='uid' and fid='fid'
strcpy(sql,"delete from relations where uid=");
sprintf(ch,"%d",file.uid);
strcat(sql,ch);
strcat(sql," and fid=");
sprintf(ch,"%d",fid);
strcat(sql,ch);
res=mysql_query(&conn,sql);
if(res)
{
printf("Delete Error\n");
}
else
{
;;
}
}
else
{
perror("Connect Failed!");
exit(-);
} mysql_close(&conn);
return rt;
}

  从上面的sql语句可以知道我们只是删除了relations表中的链接而已。而没有真正的删除已经上传上去的文件。这一点可以参考以前给过的资料。

  运行的截图如下

  文件共享给好友

  client.cpp文件加入一个函数

 int file_sendto(struct Addr addr,struct User user,char *filenames,struct User to)
{
struct sockaddr_in servAddr;
struct hostent *host;
struct Control control;
struct File file;
int sockfd; host=gethostbyname(addr.host);
servAddr.sin_family=AF_INET;
servAddr.sin_addr=*((struct in_addr *)host->h_addr);
servAddr.sin_port=htons(addr.port);
if(host==NULL)
{
perror("获取IP地址失败");
exit(-);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-)
{
perror("socket创建失败");
exit(-);
}
if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-)
{
perror("connect 失败");
exit(-);
} //控制信号
control.control=FILE_SENDTO;
control.uid=user.uid;
if(send(sockfd,(char *)&control,sizeof(struct Control),)<)
{
perror("文件指纹发送失败");
exit(-);
}
file.uid=user.uid;
strcpy(file.filename,filenames);
if(send(sockfd,(char *)&file,sizeof(struct File),)<)
{
perror("共享文件失败");
exit(-);
}
if(send(sockfd,(char *)&to,sizeof(struct User),)<)
{
perror("共享用户发送失败");
exit(-);
}
char ch[];
memset(ch,,sizeof(ch));
if(recv(sockfd,ch,sizeof(ch),)<)
{
perror("共享文件失败");
exit(-);
}
if(ch[]=='y') //删除成功
{
printf("共享成功\n");;
}
else if(ch[]=='n') //删除失败
{
if(ch[]=='')
printf("共享失败,确认是否有该文件\n");
else if(ch[]=='')
printf("共享失败,确认是否有该用户\n");
}
close(sockfd);
return ;
}

  而server.cpp在主函数main中switch中增加如下

 case FILE_SENDTO:
{
struct File file;
struct User to;
recv(clientfd,(char *)&file,sizeof(struct File),);
recv(clientfd,(char *)&to,sizeof(struct User),);
int t=mysql_sendto(file,to);
char ch[];
memset(ch,,sizeof(ch));
if(t==-)
{
printf("没有对应的文件\n");;
strcpy(ch,"no1");
send(clientfd,ch,,);
break;
}
else if(t==-)
{
printf("没有对应的用户\n");;
strcpy(ch,"no2");
send(clientfd,ch,,);
break;
}
strcpy(ch,"yes");
send(clientfd,ch,,);
printf("共享成功\n");
break;
}

  然后对应的增加下面一个函数

 int mysql_sendto(struct File file,struct User to)
{
//insert into relations values(uid,fid);
MYSQL conn;
MYSQL_RES * res_ptr;
MYSQL_ROW result_row;
int res;int row;int column;
int i,j;int fid;int uid;int rt=;
char sql[];
char ch[]; mysql_init(&conn);
if(mysql_real_connect(&conn,"localhost","root","","filetranslate",,NULL,CLIENT_FOUND_ROWS))
{
//select files.fid from files,relations where relations.fid=files.fid and filename=files.filename;
//得到fid后
strcpy(sql,"select files.fid from files,relations where relations.fid=files.fid and filename=\"");
strcat(sql,file.filename);
strcat(sql,"\";");
res=mysql_query(&conn,sql);
fid=;
if(res)
{
perror("Select Sql Error!");
}
else
{
res_ptr=mysql_store_result(&conn);
if(res_ptr)
{
column=mysql_num_fields(res_ptr);
row=mysql_num_rows(res_ptr)+;
if(row<=)
;
else
{
result_row=mysql_fetch_row(res_ptr);
if(result_row[]==NULL)
{
fid=;
}
else
{
fid=atoi(result_row[]);
}
}
}
else
{
fid=;
}
}
if(fid==)
{
mysql_close(&conn);
return -;//表示没有该文件
} //select uid from users where username=[to].username;
//得到uid后
strcpy(sql,"select uid from users where username=\"");
strcat(sql,to.username);
strcat(sql,"\"");
res=mysql_query(&conn,sql);
uid=;
if(res)
{
perror("Select Sql Error!");
}
else
{
res_ptr=mysql_store_result(&conn);
if(res_ptr)
{
column=mysql_num_fields(res_ptr);
row=mysql_num_rows(res_ptr)+;
if(row<=)
;
else
{
result_row=mysql_fetch_row(res_ptr);
if(result_row[]==NULL)
{
uid=;
}
else
{
uid=atoi(result_row[]);
}
}
}
else
{
uid=;
}
}
if(uid==)
{
mysql_close(&conn);
return -;//表示没有该用户
} //将获取到的uid fid插入到数据库relations中
//insert into relations values(uid,fid);
strcpy(sql,"insert into relations values( ");
sprintf(ch,"%d",uid);
strcat(sql,ch);
strcat(sql,", ");
sprintf(ch,"%d",fid);
strcat(sql,ch);
strcat(sql,");");
res=mysql_query(&conn,sql);
printf("==========> uid=%d fid=%d\n",uid,fid);
if(res)
{
rt=-;
printf("Insert Error\n");
}
else
{
printf("Insert Success\n");
}
}
else
{
perror("Connect Failed!");
exit(-);
}
mysql_close(&conn);
return rt;
}

  下面这个是运行时的截图

  在本次程序的最后,送上程序代码结构,及本人的开发环境。

  从程序中可以看出很多代码是有冗余的,如果进行重构的话,估计代码可以节省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

  本文地址: http://www.cnblogs.com/wunaozai/p/3893469.html

  代码下载: http://files.cnblogs.com/wunaozai/xiaoxiaowangpan.zip

Socket网络编程--小小网盘程序(5)的更多相关文章

  1. Socket网络编程--小小网盘程序(4)

    在这一小节中实现了文件的下载,具体的思路是根据用户的uid和用户提供的文件名filename联合两张表,取得md5唯一标识符,然后操作这个标识符对应的文件发送给客户端. 实现下载的小小网盘程序 cli ...

  2. Socket网络编程--小小网盘程序(2)

    这一节将不会介绍太多的技术的问题,这节主要是搭建一个小小的框架,为了方便接下来的继续编写扩展程序.本次会在上一小节的基础上加上一个身份验证的功能. 因为网盘程序不像聊天程序,网盘是属于主动向服务器拉取 ...

  3. Socket网络编程--小小网盘程序(3)

    接上一小节,这次增加另外的两张表,用于记录用户是保存那些文件.增加传上来的文件的文件指纹,使用MD5表示. 两张表如下定义: create table files( fid int, filename ...

  4. Socket网络编程--小小网盘程序(1)

    这个系列是准备讲基于Linux Socket进行文件传输.简单的文件传输就是客户端可以上传文件,可以从服务器端下载文件.就这么两个功能如果再加上身份验证,就成了FTP服务器了,如果对用户的操作再加上一 ...

  5. linux下C语言socket网络编程简例

    原创文章,转载请注明转载字样和出处,谢谢! 这里给出在linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到client的连接后,发送数据给client:clie ...

  6. 5.3linux下C语言socket网络编程简例

    原创文章,转载请注明转载字样和出处,谢谢! 这里给出在Linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端:客户端在接受到数据后 ...

  7. Socket网络编程--聊天程序(9)

    这一节应该是聊天程序的最后一节了,现在回顾我们的聊天程序,看起来还有很多功能没有实现,但是不管怎么说,都还是不错的.这一节我们将讲多服务器问题(高大上的说法就是负载问题了.)至于聊天程序的文件发送(也 ...

  8. Socket网络编程系列教程序

    C语言的用途相当多,可以用在数据结构.数据库.网络.嵌入式等方面,历经40多年不衰,真是厉害!最近一直想从某一应用方面写一个系列教程,好好地把某一方面讲深讲透.         正好博主对网络方面的编 ...

  9. Socket网络编程--FTP客户端

    Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...

随机推荐

  1. webstorm 格式化代码及常用快捷键

    mac 下 webstorm 格式化代码的快捷键 Option+Command+l windows 下 webstorm 格式化代码的快键键 Ctrl+Alt+l centOS 下webstorm 格 ...

  2. POJ 3304 Segments (叉乘判断线段相交)

    <题目链接> 题目大意: 给出一些线段,判断是存在直线,使得该直线能够经过所有的线段.. 解题思路: 如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为 ...

  3. [漏洞分析]thinkphp 5.1.25 insert、insetAll、update方法注入

    0x00 前言 这个洞,早在9月29号的时候我提交给先知,那时候tp还是5.1.25的版本,天还很蓝,我也还很年轻.时至今日这个洞依旧没有审核,而tp在这期间都已经更新到了5.1.29.在最近我去跟踪 ...

  4. Avahi DOS攻击broadcast-avahi-dos

    Avahi DOS攻击broadcast-avahi-dos   Avahi是Linux下常用的类DNS服务.它可以帮助主机在没有DNS服务的局域网中,发现基于Zeroconf协议的设备和服务.该工具 ...

  5. 洛谷.4015.运输问题(SPFA费用流)

    题目链接 嗯..水题 洛谷这网络流二十四题的难度评价真神奇.. #include <queue> #include <cstdio> #include <cctype&g ...

  6. 非常简单的方法实现ViewPager自动循环轮播

    非常简单的方法实现ViewPager自动循环轮播,见红色代码部分,其它的代码可以忽略不看. 简洁高效是我解决问题的首要出发点. package com.shuivy.happylendandreadb ...

  7. BZOJ4374 : Little Elephant and Boxes

    设$f[i][j][k]$表示前$i$个物品买了$j$个,消耗$k$个钻石,最少花多少钱,可以通过简单的DP求出. 枚举拥有的钻石数以及最多能购买的物品数的下界,那么钱数的下界是定值. 将$n$个箱子 ...

  8. javascript中的LHS与RHS

    最近在学习javascript过程中,接触了LHS与RHS的概念,刚开始的时候有点理解不清,现在做一些梳理,方便以后进行理解. LHS与RHS:javascript引擎的两种查找类型,含义是赋值操作的 ...

  9. event对象中 target和currentTarget 属性的区别。

    首先本质区别是: event.target返回触发事件的元素 event.currentTarget返回绑定事件的元素

  10. block 相关清单

    对Objective-C中Block的追探  李博士