自己想做个网站需要多少钱,潍坊做电商的网站,外包公司有哪些,东莞h5网站开发参考#xff1a;FTP云盘项目 作者#xff1a;糯米啊啊 发布时间#xff1a; 2021-08-19 10:34:05 网址#xff1a;https://blog.csdn.net/weixin_43732386?spm1001.2014.3001.5509 参考#xff1a;自制FTP云盘项目 作者#xff1a;不说话的小脑斧 发布时间#xff1a; … 参考FTP云盘项目 作者糯米啊啊 发布时间 2021-08-19 10:34:05 网址https://blog.csdn.net/weixin_43732386?spm1001.2014.3001.5509 参考自制FTP云盘项目 作者不说话的小脑斧 发布时间 2021-01-13 12:02:23 网址https://blog.csdn.net/qq_44745336/article/details/112547781?spm1001.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.hint 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-lif(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函数执行 pwdif(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
#includestring.h
#include unistd.h
#include string.h
#include sys/stat.h
#include fcntl.h
#include config.hint 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-lfread(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版 – 启用副服务器