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 ...
随机推荐
- HTTP 的长连接和短连接
一.什么是长连接 HTTP1.1规定了默认保持长连接(HTTP persistent connection ,也有翻译为持久连接),数据传输完成了保持TCP连接不断开(不发RST包.不四次握手),等待 ...
- JavaWeb 之 清理错误的无奈之举
1. Project -> Clean 2. 清空浏览器缓存 (得先按了F2,出了调试窗口,才可以右键它) 3. 右键项目 -> Maven -> Update -> Forc ...
- python的random模块(生成验证码)
python的random模块(生成验证码) random模块常用方法 random.random() #生成0到1之间的随机数,没有参数,float类型 random.randint(1, 3) # ...
- 爬虫之urllib.request基础使用(一)
urllib模块 urllib模块简介: urllib提供了一系列用于操作URL的功能.包含urllib.request,urllib.error,urllib.parse,urllib.robotp ...
- P2376 [USACO09OCT]津贴Allowance
P2376 [USACO09OCT]津贴Allowance一开始想的是多重背包,但是实践不了.实际是贪心,让多c尽可能少,所以先放大的,最后让小的来弥补. #include<iostream&g ...
- chrome浏览器调试工具你会使用吗?
浏览器调试工具使用总结 一. console使用 console.table(),可以把对象输出成表格的形式,直观的观察数据. console.dir(),可以直观观察dom元素的对象形式 二. $的 ...
- python数据分析之pandas数据选取:df[] df.loc[] df.iloc[] df.ix[] df.at[] df.iat[]
1 引言 Pandas是作为Python数据分析著名的工具包,提供了多种数据选取的方法,方便实用.本文主要介绍Pandas的几种数据选取的方法. Pandas中,数据主要保存为Dataframe和Se ...
- Springboot 2.0.x 引入链路跟踪Sleuth及Zipkin
Zipkin是一种分布式跟踪系统,它有助于收集解决微服务架构中得延迟问题所需的时序数据,它管理这些数据的收集和查找. 1. 架构概述 跟踪器存在于您的应用程序中,并记录有关发生的操作的时间和元数据.他 ...
- BZOJ.2741.[FOTILE模拟赛]L(分块 可持久化Trie)
题目链接 首先记\(sum\)为前缀异或和,那么区间\(s[l,r]=sum[l-1]^{\wedge}sum[r]\).即一个区间异或和可以转为求两个数的异或和. 那么对\([l,r]\)的询问即求 ...
- java计算某个坐标是否在范围内
java电子围栏 圆.矩形.多边形算法 http://blog.csdn.net/deepak192/article/details/79402694/ java-经纬度有关的计算(半径内的经纬度范围 ...