Socket网络编程--小小网盘程序(5)
各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中的文件列表,还有删除用户在服务器中的文件,最后的可以共享文件给好友。
列出用户在服务器中的文件列表
增加一个结构体
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)的更多相关文章
- Socket网络编程--小小网盘程序(4)
在这一小节中实现了文件的下载,具体的思路是根据用户的uid和用户提供的文件名filename联合两张表,取得md5唯一标识符,然后操作这个标识符对应的文件发送给客户端. 实现下载的小小网盘程序 cli ...
- Socket网络编程--小小网盘程序(2)
这一节将不会介绍太多的技术的问题,这节主要是搭建一个小小的框架,为了方便接下来的继续编写扩展程序.本次会在上一小节的基础上加上一个身份验证的功能. 因为网盘程序不像聊天程序,网盘是属于主动向服务器拉取 ...
- Socket网络编程--小小网盘程序(3)
接上一小节,这次增加另外的两张表,用于记录用户是保存那些文件.增加传上来的文件的文件指纹,使用MD5表示. 两张表如下定义: create table files( fid int, filename ...
- Socket网络编程--小小网盘程序(1)
这个系列是准备讲基于Linux Socket进行文件传输.简单的文件传输就是客户端可以上传文件,可以从服务器端下载文件.就这么两个功能如果再加上身份验证,就成了FTP服务器了,如果对用户的操作再加上一 ...
- linux下C语言socket网络编程简例
原创文章,转载请注明转载字样和出处,谢谢! 这里给出在linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到client的连接后,发送数据给client:clie ...
- 5.3linux下C语言socket网络编程简例
原创文章,转载请注明转载字样和出处,谢谢! 这里给出在Linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端:客户端在接受到数据后 ...
- Socket网络编程--聊天程序(9)
这一节应该是聊天程序的最后一节了,现在回顾我们的聊天程序,看起来还有很多功能没有实现,但是不管怎么说,都还是不错的.这一节我们将讲多服务器问题(高大上的说法就是负载问题了.)至于聊天程序的文件发送(也 ...
- Socket网络编程系列教程序
C语言的用途相当多,可以用在数据结构.数据库.网络.嵌入式等方面,历经40多年不衰,真是厉害!最近一直想从某一应用方面写一个系列教程,好好地把某一方面讲深讲透. 正好博主对网络方面的编 ...
- Socket网络编程--FTP客户端
Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...
随机推荐
- 057 Hive项目案例过程
1.说明 这里只粘贴一张,图,主要针对的hive的项目的实践过程. 2.图 3.需求 统计PV 统计注册人数 => 这个是一个公司会关注的,每天的注册率. 统计ip 统计跳出率 => ip ...
- go语言学习-常用命令
前面的文章中记录了安装 golang 和配置开发环境,本文将学习的 go 命令行命令以及使用场景. 查看可用命令 直接在终端中输入 go help 即可显示所有的 go 命令以及相应命令功能简介,主要 ...
- SQL Server中查找包含某个文本的存储过程
SELECT name,text from sysobjects o,syscomments s where o.id=s.id and text LIKE '%text%' and o.xtype= ...
- Css实现元素的垂直居中
前言: 在写CSS的时候让元素在高度固定的容器中垂直居中是很简单的,譬如设置容器的padding或者元素的margin之类的都可以做到:让元素在容器中水平居中也有text-align:center.m ...
- jQuery.when().done()
在使用jQuery.when()调用外部声明方法时,如果方法不为Deferred(延时)对象,则done会立即执行,所有需要在调用的方法声明一个var deferred = $.Deferred(); ...
- php 字符串翻转
字符串翻转 <?php$s = 'strlen,substr,count';$o = '';$i = 0;while(isset($s[$i]) && $s[$i] != nul ...
- 47. 全排列 II
47. 全排列 II 题意 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2]输出:[ [1,1,2], [1,2,1], [2,1,1]] 解题思路 去重的全排列 ...
- 19 个必须知道的 Visual Studio 快捷键
项目相关的快捷键 Ctrl + Shift + B = 生成项目 Ctrl + Alt + L = 显示Solution Explorer(解决方案资源管理器) Shift + Alt+ C = 添加 ...
- 【译】如何在 Android 5.0 上获取 SD卡 的读写权限
因为最近项目需要,涉及到 SD卡 的读写操作,然而申请 <!-- 读写权限 --> <uses-permission android:name="android.permi ...
- asp.net c#并行调用service层代码
public ActionResult Home(AdviserSearchModel model) { //顾问列表需要的当前城市的下级地区 var ip = "117.82.196.19 ...