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 ...
随机推荐
- 【Java】 剑指offer(31) 栈的压入、弹出序列
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否 ...
- java连接数据库(jdbc)调用配置文件
各种语言都有自己所支持的配置文件,后缀名“.properties”结尾的就是其中之一. 在java连接数据库时,采取读取配置文件的方式,来获取数据库连接. 新建jdbc.properties文件,内容 ...
- 全排列问题(递归&非递归&STL函数)
问题描述: 打印输出1-9的所有全排序列,或者打印输出a-d的全排列. 思路分析: 将每个元素放到余下n-1个元素组成的队列最前方,然后对剩余元素进行全排列,依次递归下去. 比如:1 2 3 为例首先 ...
- Sea Battle CodeForces - 729D
题意: 有n个格子,a条船,每条船占b个格子.事先已经射击了k个格子,且这k次射击不会射到船上,求再射击几次可以射到某一条船的某一部分 思路: 观察样例可以发现,如果五个0,船的长度是3,那么这五个0 ...
- bzoj 4767: 两双手 组合 容斥
题目链接 bzoj4767: 两双手 题解 不共线向量构成一组基底 对于每个点\((X,Y)\)构成的向量拆分 也就是对于方程组 $Ax * x + Bx * y = X $ \(Ay * x + B ...
- Python数据可视化系列-01-快速绘图
快速绘图 数据图绘制 matplotlib的字库pyplot提供了快速绘制2D图标的API接口. import numpy as np import matplotlib.pyplot as plt ...
- Python中的MySQLConnector使用介绍
MySQL Connector/Python 是 MySQL 官方提供的 Python 连接 MySQL 数据库的驱动程序了,很多初学者对于 在python中连接mysql数据库还是有点为难了,下文我 ...
- CocosCreator的节点显示和隐藏
隐藏和显示有两种方式: 1.禁止节点node的运行,方法是x.node.active=false[此时隐藏了节点,且节点不再运行];恢复节点正常运行,x.node.active=true;或者使用x. ...
- 关于RabbitMQ关键性问题的总结
摘要:本篇是本人对RabbitMQ使用的关键性问题进行的总结,如性能上限.数据存储.集群等, 具体的RabbitMQ概念.安装.使用方法.SpringAMQP配置,假设读者已有了基础. 1. ...
- MX4_ADB
一.Ubuntu环境1. 建立或修改文件 ~/.android/adb_usb.ini,在文件开头或末尾添加一行,内容是0x2a45. 2. 建立或修改文件 /etc/udev/rules.d/51- ...