FTP云盘

参考:FTP云盘项目
作者:糯米啊啊
发布时间: 2021-08-19 10:34:05
网址:https://blog.csdn.net/weixin_43732386?spm=1001.2014.3001.5509

参考:自制FTP云盘项目
作者:不说话的小脑斧
发布时间: 2021-01-13 12:02:23
网址:https://blog.csdn.net/qq_44745336/article/details/112547781?spm=1001.2014.3001.5502

以及:https://blog.csdn.net/zouchengzhi1021/article/details/113668089

目录

  • 项目简介
  • 功能说明
  • 代码编写
    • config.h
    • 服务端
    • 客户端
  • 运行效果
  • V2.0版 -- 启用副服务器

项目简介

FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。 FTP是File Transfer
Protocol(文件传输协议)。
程序运行,服务端不断接收客户端指令,服务端可同时处理多个客户端接入并对指令作出解析,并把执行结果返回给客户端,客户端根据服务端对指令的解析并把由服务端传递过来的处理信息通过客户端呈现给客户,实现文件的各种操作。

可作为嵌入式面试话术使用

这个项目分成ftp客户端及服务端,实现的功能和Linux开源的ftp服务器类似,客戶端通过网络,远程获取服务端磁盘上的文件夹内容,下载文件,上传文件等功能。(基本功能描述)

ftp服务器用到的是Socket通信,当收到客户端接入的时候,创建子进程对接连接,子进程启动后分析来自客户端的指令,比如收到get file1的指令,是客户端想要获取file1文件的,我先用strstr函数进行字符串分割,获取到文件名,在判断文件是否存在,如果文件存在,就读取文件內容,再将內容通过套接字发给客户端,客户端收到数据后,创建文件,并将收到的数据写入文件,完成文件的远程下载。(说明网络编程,字符串编程,文件编程的功底)

上传文件和下载文件类似,主要还是涉及文件的操作,字符串的操作,以及网络编程。

还支持了Is’pwd,cd等Linux系统常用的指令。普通指令的实现用popen来调用系统质量,并读取执行的结构。如果不需要获取执行结果,用system函数调用就可以了。(说明popen,system的编程)

这个项目我是来锻炼我的LinUx系统编程能力的,在学习系统编程的时候,我还学习了进程间通信,如管道,信号,共享内存,消息队列等。现在正在优化这个项目,想把这块知识用到项目中去,下次遇到项目的话就比较得心应手,做开发就是要多多折腾嘛。

功能说明

本文是基于Linux网络编程实现的FTP服务器,服务器由服务端和客户端组成,具有浏览远程服务端的文件和浏览客户端本地文件,同时支持对远程服务端文件的删除,存储,归档操作处理,以及客户端对远程服务端文件的上传和下载。

利用socket实现云盘的基本功能:

  • ls———查看服务端文件
  • lls———查看客户端自己的文件
  • cd———切换服务端目录
  • lcd———切换客户端自己的目录
  • put———上传文件
  • get———下载文件
  • pwd———显示路径
  • quit———退出

代码编写

config.h

#define LS		1
#define LLS		2
#define CD		3
#define GET		4
#define PUT		5
#define PWD		6
#define QUIT	0typedef struct msg			//传递信息的结构体
{int type;//没有用到char cmd[128];//存放命令char data_buf[1024];//存放文件内容
}Msg;

服务端

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config.h"int Analysis_Command(char *buf)		//分析命令
{//int strcmp(const char *s1, const char *s2);//字符串比较if(strcmp("ls",buf)==0)  				return LS;if(strcmp("pwd",buf)==0)  				return PWD;if(strcmp("quit",buf)==0)				return QUIT;if(strcmp("lls",buf)==0)				return LLS;//char *strstr(const char *haystack, const char *needle);//搜索一个字符串在另一个字符串中的第一次出现if(strstr(buf,"cd")!=NULL && strstr(buf,"lcd")==NULL)	return CD;if(strstr(buf,"get")!=NULL)				return GET;//因为用户输入指令 带参数if(strstr(buf,"put")!=NULL)				return PUT;return -1;
}char *getDirName(char *cmd)		//获取文件名  最好定义成 get_dir(函数名 变量名)
{char *fileName = NULL;//char *strtok(char *s, char *delim)//分解字符串 str 为一组字符串,delim 为分隔符,返回值:分隔符匹配到的第一个子串fileName = strtok(cmd," ");		//分割字符串fileName = strtok(NULL," ");	//strtok函数固定用法	return fileName;
}int dowork(int *c_fd)  //函数名规范定义 msgs_Handler
{int cmd = 666;		//无效的值FILE *p_fd;			//popen的返回值类型int n_read;				char *file_name = NULL;Msg r_msg_buf;		//socket通信间信息的载体Msg w_msg_buf;		//socket通信间信息的载体memset(&r_msg_buf,0,sizeof(Msg));memset(&w_msg_buf,0,sizeof(Msg));// ssize_t recv(int sockfd, void *buf, size_t len, int flags);//与read功能类似//视频里讲 用read读完就没了 这里使用recv返回值为0判断客户端断开连接//ssize_t read(int fd, void *buf, size_t count);read(*c_fd,&r_msg_buf,sizeof(Msg));		//从socket套接字中读取命令cmd = Analysis_Command(r_msg_buf.cmd);	//分析命令switch(cmd){     //客户端那边也有一样的这些指令   相互对接case LS:p_fd = popen("ls -l","r");	//调用popen函数执行 "ls-l"if(p_fd == NULL)		//判断是否popen成功{printf("popen error\n");exit(-1);}	fread(w_msg_buf.data_buf,1024,1,p_fd);//从块设备读到缓存write(*c_fd,&w_msg_buf,sizeof(Msg)); //缓存发给客户端,客户端调用read获得结果fclose(p_fd);		//关闭printf("get cmd : %s\n",r_msg_buf.cmd);		//服务端调试信息break;case PWD:		//pwd和ls一样p_fd = popen("pwd","r");//调用popen函数执行 "pwd"if(p_fd == NULL){printf("popen error\n");exit(-1);}fread(w_msg_buf.data_buf,1024,1,p_fd);//将popen执行结果放在w_msg_buf.data_buf中write(*c_fd,&w_msg_buf,sizeof(Msg));//通过套接字将w_msg_buf.data_buf写到客户端吗,客户端调用read,然后输出即可获得结果fclose(p_fd);printf("get cmd : %s\n",r_msg_buf.cmd);//服务端调试信息break;case LLS:printf("get cmd : lls\n"); 		//lls指令是打印出客户端该目录下的文件,所以服务端不做操作,只打印一个调试信息break;case GET:file_name = getDirName(r_msg_buf.cmd);//获取文件名if(access(file_name,F_OK)==0)//通过文件名判断文件是否存在{int fd = open(file_name,O_RDWR);read(fd,w_msg_buf.data_buf,1024);write(*c_fd,&w_msg_buf,sizeof(Msg));//如果存在,即打开,读取,写入。close(fd);}else{strcpy(w_msg_buf.data_buf,"no this document!");//不存在则写入"no this document!"write(*c_fd,&w_msg_buf,sizeof(Msg));}printf("get cmd : %s %s\n",r_msg_buf.cmd,file_name);break;case CD:		//进入服务端某文件夹file_name = getDirName(r_msg_buf.cmd);//(分割)获取文件夹名if(access(file_name,F_OK)==0)//判断该文件是否存在{//int chdir(const char *path)//改变当前工作目录chdir(file_name);//系统调用函数(同cd)改变当前目录,即进入了文件夹//不能用system(源码是fork 另起了一个shell  这里要求自己进入文件夹)strcpy(w_msg_buf.data_buf,file_name);write(*c_fd,&w_msg_buf,sizeof(Msg));}else{strcpy(w_msg_buf.data_buf,"the server no have this file directory!");//如果没有则写入"the server no have this file directory!"write(*c_fd,&w_msg_buf,sizeof(Msg));}printf("get cmd : %s %s\n",r_msg_buf.cmd,file_name);//服务端调试信息break;case PUT:		//上传某文件到服务端file_name = getDirName(r_msg_buf.cmd);read(*c_fd,&r_msg_buf,sizeof(Msg));if(strcmp(r_msg_buf.data_buf, "The client no have this document!") != 0){if(access(file_name,F_OK)==0) //如果文件存在{int fd = open(file_name,O_RDWR|O_TRUNC);//调用O_TRUNC将源文件内容删除,写入新内容write(fd,r_msg_buf.data_buf,strlen(r_msg_buf.data_buf));close(fd);}else{int fd = creat(file_name, 0666);//如果不存在,创建if(fd == -1){perror("creat error!\n");}if(write(fd, r_msg_buf.data_buf, strlen(r_msg_buf.data_buf)) == -1)//写入新内容{perror("write error!\n");}close(fd);}}printf("get cmd : %s %s\n",r_msg_buf.cmd,file_name);break;case QUIT:		//客户端退出write(*c_fd, &w_msg_buf, sizeof(Msg));printf("=====client exit=====\n");close(*c_fd);exit(0);break;case -1:strcpy(w_msg_buf.data_buf, "Command error!");//指令错误write(*c_fd, &w_msg_buf, sizeof(Msg));printf("===== cmd error =====\n");break;}return 0;
}int main(int argc,char *argv[]) 
{	int s_fd;int c_fd;struct sockaddr_in s_addr; struct sockaddr_in c_addr;	//socket套接字所需要的结构体memset(&s_addr,0,sizeof(struct sockaddr_in));//清空memset(&c_addr,0,sizeof(struct sockaddr_in));int clen = sizeof(struct sockaddr_in);if(argc != 3){	//判断运行时传参是否正确printf("param error\n");exit(-1);}s_addr.sin_family = AF_INET;s_addr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1],&(s_addr.sin_addr));//1.socket//创建套接字//int socket(int domain, int type, int protocol);s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd == -1){printf("socket error\n");perror("why");}//2.bind 绑定IP号及端口//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);if(bind(s_fd,(struct sockaddr *)&s_addr,clen) == -1){printf("bind error\n");perror("why");}//3.lieten 监听// int listen(int sockfd, int backlog);if(listen(s_fd,10) == -1){printf("listen error\n");}while(1){//4.accept 连接//int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);if(c_fd == -1){printf("accept error\n");perror("why");}if(fork()==0){		//有客户端连接,创建子进程来对接printf("***hava client***\n");while(1){dowork(&c_fd);}}}close(s_fd);return 0;
}

客户端

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include<string.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config.h"int Analysis_Command(char *buf)//分析指令
{if(strcmp(buf,"ls")==0)		return LS;if(strcmp(buf,"lls")==0)	return LLS;if(strcmp(buf,"pwd")==0)	return PWD;if(strcmp(buf,"quit")==0)	return QUIT;if(strstr(buf,"cd")!=NULL && strstr(buf,"lcd")==NULL)	return CD;if(strstr(buf,"get")!=NULL)	return GET;if(strstr(buf,"put")!=NULL)	return PUT;return -1;
}char *getDirName(char *cmd)//获取文件名
{char *file_Name = NULL;file_Name = strtok(cmd," ");file_Name = strtok(NULL," ");//strtok函数固定用法return file_Name;
}int doWork(int *c_fd)
{int cmd = 666;//无效的值FILE *p_fd;//popen的返回类型为FILE*char *file_name = NULL;Msg w_msg_buf;Msg r_msg_buf;//套接字信息传递过程中的载体memset(&w_msg_buf,0,sizeof(Msg));memset(&r_msg_buf,0,sizeof(Msg));//清空printf(">>");gets(w_msg_buf.cmd);//获取用户输入write(*c_fd,&w_msg_buf,sizeof(Msg));//将用户输入的指令写入套接字中,供服务端读取cmd = Analysis_Command(w_msg_buf.cmd);//分析指令printf("*****************************\n");printf("\n");switch(cmd){case LS:read(*c_fd,&r_msg_buf,sizeof(Msg));//读取客户端popen的返回内容printf("%s",r_msg_buf.data_buf);//打印printf("***********************\n");break;case PWD:read(*c_fd,&r_msg_buf,sizeof(Msg));//读取客户端popen的返回内容printf("%s",r_msg_buf.data_buf);//打印printf("***********************\n");break;case LLS:p_fd = popen("ls -l","r");//调用popen函数执行"ls-l"fread(r_msg_buf.data_buf,1024,1,p_fd);//客户端自己读取自己popen返回的内容printf("%s\n",r_msg_buf.data_buf);//打印fclose(p_fd);break;case GET:	//下载文件read(*c_fd,&r_msg_buf,sizeof(Msg));//读取客户端写入来的文件内容file_name = getDirName(w_msg_buf.cmd);//获取文件名if(strcmp(r_msg_buf.data_buf,"no this document!")==0){printf("%s\n",r_msg_buf.data_buf);}else{if(access(file_name,F_OK)==0)//判断文件是否存在{int fd = open(file_name,O_RDWR|O_TRUNC);//存在即打开,O_TRUNC作用是将源文件内容全部删除以方便写入新内容if(fd==-1){printf("open error!\n");perror("why");}else{int w_ret = write(fd,r_msg_buf.data_buf,strlen(r_msg_buf.data_buf));//写入内容if(w_ret==-1){printf("write error!\n");perror("why");}close(fd);}}else{int fd = creat(file_name, 0666);//不存在即创建if(fd == -1){perror("creat error: ");}if(write(fd, r_msg_buf.data_buf, strlen(r_msg_buf.data_buf)) == -1)//写入{perror("write error: ");}close(fd);}printf("%s download success!\n",file_name);//提示下载成功}break;case CD:	//进入某文件夹read(*c_fd,&r_msg_buf,sizeof(Msg));if(strcmp(r_msg_buf.data_buf,"the server no have this file directory!")==0){printf("%s\n",r_msg_buf.data_buf);}else{printf("enter %s\n",r_msg_buf.data_buf);}printf("get cmd: CD\n");break;case PUT:	//上传某文件至服务端file_name = getDirName(w_msg_buf.cmd);if(access(file_name, F_OK) == 0){int fd = open(file_name, O_RDWR);read(fd, w_msg_buf.data_buf, 1024);write(*c_fd, &w_msg_buf, sizeof(Msg));close(fd);}else{strcpy(w_msg_buf.data_buf,"The client no have this document!");write(*c_fd,&w_msg_buf,sizeof(Msg));printf("%s\n",w_msg_buf.data_buf);}printf("get cmd : put %s\n",file_name);break;case QUIT:exit(0);break;default :read(*c_fd, &r_msg_buf, sizeof(Msg));printf("%s\n", r_msg_buf.data_buf);break;}return 0;
}int main(int argc,char *argv[])
{int c_fd;struct sockaddr_in c_addr;if(argc != 3){printf("param error\n");exit(-1);}int clen = sizeof(struct sockaddr);memset(&c_addr,0,sizeof(struct sockaddr_in));//1.socket//创建套接字//int socket(int domain, int type, int protocol);c_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd == -1){printf("client socket error\n");perror("why");}c_addr.sin_family = AF_INET;c_addr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1],&(c_addr.sin_addr));//2.connect 连接//客户连接主机//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);if(connect(c_fd,(struct sockaddr *)&c_addr,clen) == -1){printf("conncet error\n");perror("why");}while(1){doWork(&c_fd);}return 0;
}

运行效果

在这里插入图片描述

V2.0版 – 启用副服务器

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265281.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html transform属性,css3 transform属性详解

CSS3变形是一些效果的集合&#xff0c;比如平移translate() 、旋转rotate()、缩放scare()和倾斜skew()效果&#xff0c;每个效果都被称作为变形函数(Transform Function),它们可以操控元素发生旋转、缩放、和平移等变化。CSS3的2D transform函数包括了translate()、scale()、ro…

PHP调用新浪API 生成短链接

我们经常收到类似于这样的短信&#xff08;如下图&#xff09;&#xff0c;发现其中的链接并不是常规的网址链接&#xff0c;而是个短小精悍的短链接&#xff0c;产品中经常需要这样的需求&#xff0c;如果在给用户下发的短信中是一个很长的连接&#xff0c;用户体验肯定很差&a…

Chrome如何下载网页视频

目录第一步&#xff1a;右键&#xff0c;选择「检查」指令&#xff0c;进入代码控制面板第二步&#xff1a;单击代码面板左上角红色标出来的按钮&#xff0c;然后鼠标移到左边视频上第三步&#xff1a;双击src后面的代码&#xff08;全部展开&#xff09;&#xff0c;复制粘贴到…

单链表反转

参考&#xff1a;【图文解析】反转一个单链表 作者&#xff1a;giturtle 发布时间&#xff1a; 2019-03-18 15:26:38 网址&#xff1a;https://blog.csdn.net/qq_42351880/article/details/88637387?spm1001.2014.3001.5501 目录例题描述思路代码实现例题描述 反转一个链表 …

MODBUS通讯协议详解(基于485)

参考&#xff1a;灵育科技Modbus课程总结 作者&#xff1a;Naunyang 时间&#xff1a;2020-11-23 13:51:58 网址&#xff1a;https://blog.csdn.net/Naunyang/article/details/108740456?spm1001.2014.3001.5502 参考&#xff1a;MODBUS用于单片机通讯 作者&#xff1a;hillch…

C\C++与Java中的static关键字

C\C里面的static&#xff1a; 面向过程的static&#xff1a; 在c和c面向过程的设计里&#xff0c;在全局变量前加上static关键字则可将该变量定义为一个静态全局变量&#xff0c;比如&#xff1a; static int a; 那么c和c中的静态全局变量有什么特点呢&#xff1a; 1、 变…

步进电机、伺服电机、舵机、无刷电机、有刷电机区别

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

PID算法实现温控

参考&#xff1a;PID算法 作者&#xff1a;hillchina 发布时间&#xff1a; 2016-09-28 21:48:04 网址&#xff1a;https://www.bilibili.com/video/BV1Ds411t7Hr 以上完整的视频教程在腾讯课堂里有&#xff0c;在腾讯课堂里搜索PID&#xff0c;找到灵育科技&#xff0c;课程对…

[Unity3d]多个摄像机叠加效果

今天学习到一个多个摄像机看到的场景在同一个层显示&#xff0c;比如我们做一个类似反光镜的效果&#xff0c;当然反光镜可以直接用Shader来实现&#xff0c;但我就是了实现一个类比这样的一个效果&#xff0c;一个摄像机将看到的图像显示到一个Texture上&#xff0c;然后将Tex…

Java关键字final使用详解

2019独角兽企业重金招聘Python工程师标准>>> http://docs.oracle.com/javase/tutorial/java/IandI/final.htmlWriting Final Classes and MethodsYou can declare some or all of a classs methods final. You use the final keyword in a method declaration to in…

一行代码揭开CPU执行原理

参考&#xff1a;一行代码&#xff0c;揭开CPU执行原理&#xff01; 作者&#xff1a;嵌入式ARM 网址&#xff1a;https://mp.weixin.qq.com/s/qFnKhWqBGRCFAnp_KC1dmw 目录1、高级语言2、编译链接3、机器指令4、指令格式5、执行指令拓展总结很多刚刚入坑的小白可能对此完全没有…

redhat 挂载 iso文件 提示 mount :not a directory

redhat 挂载 iso文件 提示 mount :not a directory posted on 2013-12-28 22:26 秦瑞It行程实录 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/ruiy/p/errors.html

C语言常见编译错误及分析

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

面经——嵌入式常见面试题总结100题(上)

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

计算机专业运动会口号,运动会口号押韵有气势 计算机系霸气口号

淡泊明志&#xff0c;宁静致远&#xff0c;团结友爱&#xff0c;顽强拼搏。下面是文艺范收集的运动会口号押韵有气势&#xff0c;计算机系霸气口号&#xff0c;欢迎阅读收藏。1、球进了球&#xff0c;分了就会&#xff0c;不怕**&#xff0c;战无不胜。2、阳光运动&#xff0c;…

1. 观察者模式总结(C++)

1. 介绍 观察者模式&#xff1a;定义了一种“一对多”的依赖关系&#xff0c;让多个观察者对象同时监听一个对象的改变&#xff0c;即当该对象的状态发现改变时&#xff0c;会通知所有它依赖的观察者对象。观察者模式属于行为模式。 意图&#xff1a;定义对象间的一种一对多的依…

面经——嵌入式常见面试题总结100题(下)

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

学计算机要不要护发,脱发平时应该注意什么 四个妙招教你如何防止脱发

头发一掉&#xff0c;失去的不仅仅是发丝&#xff0c;还有美丽与颜值&#xff0c;一把把辛酸泪只能往肚子里吞。秃头星人们&#xff0c;如果已经脱发了&#xff0c;日常一定要加倍注意哦&#xff0c;一些错误的护发方法不要踩坑&#xff0c;护理、食疗、良好的生活作息&#xf…

面经——嵌入式软件工程师ARM体系与架构相关

参考&#xff1a;嵌入式软件工程师笔试面试指南-ARM体系与架构 作者&#xff1a;嵌入式与Linux那些事 发布时间&#xff1a; 2021-04-28 15:22:06 网址&#xff1a;https://blog.csdn.net/qq_16933601/article/details/116234673 目录 ARM体系与架构硬件基础NAND FLASH 和NOR F…

下列属于计算机人工智能应用领域的是多选题,每天五道选择题(10)

原标题&#xff1a;每天五道选择题(10)1.在Windows7操作系统中&#xff0c;磁盘维护包括硬盘检查、磁盘清理和碎片整理等功能&#xff0c;磁盘清理的目的是( )。A.提高磁盘存取速度B.获得更多磁盘可用空间C.优化磁盘文件存储D.改善磁盘的清洁度▼答案&#xff1a;B【解析】磁盘…