ftp服务器搭建类似云盘功能代码(带注释详解代码)
ftp服务器使用说明
运行服务端
./server 本机IP地址 端口号(使用ifconfig查看本机IP 地址)运行客户端 ./client 服务器IP地址 相同端口号
运行成功后可执行以下指令,实现类似云盘功能
指令说明
- ls —— 查看服务端当下目录
- lls —— 查看客户端当下目录
- pwd —— 查看服务端当前路径
- quit —— 客户端退出连接
- cd name —— 令服务器进入到name路径下下
- get name —— 从服务器上下载name文件
- put name ——将客户端name文件上传到服务器
一、头文件defin.h——存储指令及数据
#define ls 1
#define pwd 2
#define cd 3
#define get 4
#define put 5
#define lls 6
#define quit 7struct Msg
{char com[100];//存储指令char buf[1024];//存储数据
};
二、服务器server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defin.h"
#include "sys/types.h"
#include <unistd.h>
#include "sys/socket.h"
#include <arpa/inet.h>void ErrorReason(char *err,int count,int Errnum);
int Msg_Process(int SonId,char *Cmd);
int JudgeCmd(char *Cmd);
char *MsgPerform(int SonId,int Cmd,struct Msg *msg);
char *comcut(struct Msg *msg);int count=0;
int main(int argc,char **argv)
{if(argc!=3){printf("error argc\n");exit(-1);}int cp1;//用于辅助程序算法而设的标志位int soc=socket(AF_INET,SOCK_STREAM,0);//创建套接字ErrorReason("socket",soc,-1);struct sockaddr_in soc_init;struct in_addr soc_initaddr;memset(&soc_init,0,sizeof(struct sockaddr_in));memset(&soc_initaddr,0,sizeof(struct in_addr)); soc_init.sin_family=AF_INET;soc_init.sin_port=htons(atoi(argv[2]));inet_aton(argv[1],&soc_initaddr);soc_init.sin_addr.s_addr=soc_initaddr.s_addr;cp1=bind(soc,(struct sockaddr *)&soc_init,sizeof(struct sockaddr));//把地址和端口号组合赋给socketErrorReason("bind",cp1,-1);cp1=listen(soc,10);//监听连接请求,最大连接数10ErrorReason("listen",cp1,-1);struct sockaddr_in soc_on;int len=sizeof(struct sockaddr_in);int acc;pid_t id;struct Msg strdata;//用于存储指令和数据的结构体int sizlen;//指针,文件等的长度int strcmd;//存储宏定义后的指令char *pdata=NULL;//存储指令执行后的数据memset(&strdata,0,sizeof(struct Msg));while(1){count++;//用于区分客户端而设的标志位acc=accept(soc,(struct sockaddr *)&soc_on,(socklen_t *)&len);//等待客户端接入ErrorReason("accept",acc,-1);id=fork();//创建子进程与客户端完成对接ErrorReason("fork",id,-1);if(id==0)//创建子进程与客户端完成对接{while(1){memset(strdata.com,'\0',sizeof(strdata.com));sizlen=recv(acc,(void *)(strdata.com),sizeof(strdata.com),0);//阻塞直到客户端向服务端发送数据if(sizlen>0)//数据正常处理{strcmd=Msg_Process(acc,strdata.com);//返回可执行的命令if(strcmd==0)//如果命令有问题,则进入{send(acc,(void *)"error cmd",strlen("error cmd"),0);continue;}printf("1:%s\n",strdata.com);pdata=MsgPerform(acc,strcmd,&strdata);//处理命令,返回命令执行后的数据printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");if(strcmp(strdata.com,"lls")){len=send(acc,(void *)pdata,strlen(pdata),0);//向客户端发送数据}}elseif(sizlen==0)//数据有问题处理{printf("recv\n");break;}}}}close(soc);close(acc);return 0;
}int Msg_Process(int SonId,char *Cmd)//处理客服端发送的命令,返回优化后的命令
{char *strcmd=Cmd;int runcmd;runcmd=JudgeCmd(strcmd);//返回优化后的指令return runcmd;
}int JudgeCmd(char *Cmd)//优化命令
{char *p=NULL;if(!strcmp(Cmd,"ls")) return ls;elseif(!strcmp(Cmd,"pwd")) return pwd;elseif(strstr(Cmd,"cd")!=NULL) return cd;elseif(strstr(Cmd,"get")!=NULL) return get;elseif(strstr(Cmd,"put")!=NULL) return put;elseif(strcmp(Cmd,"lls")==0) return lls;elseif(strcmp(Cmd,"quit")==0) return quit;else return 0;
}char *MsgPerform(int SonId,int Cmd,struct Msg *msg)//执行命令,返回命令结果
{struct Msg *macom=msg;long len;//指针,文件等的长度int cp1;//用于辅助程序算法而设的标志位char *str=NULL;//用于返回可执行的命令(字符串)char str1[100]={'\0'};//用于返回可执行的命令(字符串)char data[1024]={'\0'};char *retudata=NULL;//执行命令后的数据存储区FILE *fp=NULL;//打开文件用的文件描述符switch(Cmd){case ls:case pwd://执行服务端shll指令{if(!strcmp((macom->com),"ls")){fp=popen("/bin/ls","r");//建立管道IO}elseif(!strcmp((macom->com),"pwd")){fp=popen("/bin/pwd","r");//建立管道IO}if(fp==NULL){perror("popen");return "popen error";}fread(data,sizeof(char),sizeof(data),fp);//读执行shll指令得到的数据fclose(fp);retudata=data;len=strlen(retudata);return retudata;//返回执行指令得到的数据}break;case cd://服务端跳转文件夹{strcpy(str1,comcut(macom));//分割macom->com字符串,返回可执行命令cp1=chdir(str1);//进入路径为str的文件夹if(cp1==-1){return "error cmd";}getcwd(data,sizeof(data));//把当前目录赋值给dataretudata=data;len=strlen(retudata);return retudata;//返回当前目录(字符串)}break;case get://从服务器上下载文件到客户端{strcpy(str1,comcut(macom));//分割macom->com字符串,返回可执行命令fp=fopen(str1,"r");//打开str文件if(fp==NULL){return "error cmd";}fseek(fp,0,SEEK_END);//把光标移动到文件流尾len=ftell(fp);//取得文件流光标所在位置,读取文件大小fseek(fp,0,SEEK_SET);//把光标移动到文件流首len=fread((void *)data,sizeof(char),len,fp);//读取文件内容retudata=data;fclose(fp);return retudata;//返回读取到的文件数据}break;case put://将客户端文件上传到服务器{memset(macom->buf,'\0',sizeof(macom->buf));recv(SonId,(void *)(macom->buf),sizeof(macom->buf),0);if(!(strcmp(macom->buf,"error")))//进入数据错误处理{return "error cmd";}strcpy(str1,(macom->com)+4);//拷贝com指令后面的文件名(字符串)fp=fopen(str1,"w+");//创建文件str1if(fp==NULL){return "error cmd";}len=strlen(macom->buf);fwrite((void *)(macom->buf),sizeof(char),len,fp);//写入数据到文件fclose(fp);return "put OK";}break;case lls://查看客户端当下目录{return "lls";}break;case quit://客户端退出(子进程退出){printf("%dProcess exits\n",count);//服务端输出提示哪个进程退出,count为标志位exit(3);//子进程退出}break;default:return "error com";}
}char *comcut(struct Msg *msg)//分割字符串,后处理字符串
{int i=0;int j=0;//用于辅助程序算法而设的标志位char *p=NULL;//处理分割字符串用的辅助位char *comaddr[10]={"NULL"};//存储分割字符串后的数据而设的指针数组char str[100]={'\0'};char str1[300]={'\0'};//存储命令处理后的数据p=strtok(msg->com," ");//分割字符串while(p!=NULL)//处理分割字符串{comaddr[i]=p;p=strtok(NULL," ");i++;}for(j=0;j<i-1;j++)//重修拼合指针数据的字符串{if(!strcmp(comaddr[0],"cd")){sprintf(str,"/%s",comaddr[j+1]);}elseif(!(strcmp(comaddr[0],"get"))){sprintf(str,"%s",comaddr[j+1]);}strcpy(str1,strcat(str1,str));}p=str1;return p;
}void ErrorReason(char *err,int count,int Errnum)//处理错误函数
{if(count==Errnum){perror(err);exit(-1);}return;
}
客户端client.c
#include <stdio.h>
#include "defin.h"
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>void ErrorReason(char *err,int count,int Errnum);
int Msg_Process(int SonId,struct Msg *Cmd);
int JudgeCmd(struct Msg *Cmd);
struct Msg *PutCom(int SonId,int Cmd,struct Msg *msg);
struct Msg *GetBuf(int SonId,int Cmd,struct Msg *msg);int main(int argc,char **argv)
{if(argc!=3){printf("error argc\n");exit(-1);}int cp1;int soc=socket(AF_INET,SOCK_STREAM,0);//创建套接字ErrorReason("socket",soc,-1);struct sockaddr_in soc_in;struct in_addr in_a;memset(&soc_in,0,sizeof(struct sockaddr_in));memset(&in_a,0,sizeof(struct in_addr)); soc_in.sin_family=PF_INET;soc_in.sin_port=htons(atoi(argv[2]));inet_aton(argv[1],&in_a);soc_in.sin_addr.s_addr=(in_a.s_addr);cp1=connect(soc,(struct sockaddr *)&soc_in,sizeof(struct sockaddr_in));//发起连接指定的网络地址ErrorReason("connect",cp1,-1);struct Msg strdata;struct Msg *getdata=(struct Msg *)malloc(sizeof(struct Msg));//用于存储服务端发送的数据int len;//用于计算指针、字符串长度等int strcmd;while(1){memset(strdata.com,'\0',sizeof(strdata.com));fgets(strdata.com,sizeof(strdata.com),stdin);//获取命令len=strlen(strdata.com);*(strdata.com+len-1)='\0';strcmd=Msg_Process(soc,&strdata);//返回可执行的命令if(strcmd==0)//如果命令有问题,则进入{printf("error cmd\n");continue;}PutCom(soc,strcmd,&strdata);//向服务端发送命令memset(getdata->buf,'\0',sizeof(getdata->buf));getdata=GetBuf(soc,strcmd,&strdata);//返回命名执行后的数据(返回服务端发送过来的的数据)printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");if(strcmd==lls){system("/bin/ls");}else{printf("main:%s\n",getdata->buf);}printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");}close(soc);return 0;
}int Msg_Process(int SonId,struct Msg *Cmd)//返回可执行的命令
{struct Msg *p=Cmd;int runcmd;runcmd=JudgeCmd(p);return runcmd;
}int JudgeCmd(struct Msg *Cmd)//优化命令
{struct Msg *p=Cmd;if(!strcmp(p->com,"ls")) return ls; elseif(!strcmp(p->com,"pwd")) return pwd; elseif(strstr(p->com,"cd")!=NULL) return cd; elseif(strstr(p->com,"get")!=NULL) return get; elseif(strstr(p->com,"put")!=NULL) return put; elseif(!strcmp(p->com,"lls")) return lls; elseif(!strcmp(p->com,"quit")) return quit;elsereturn 0;
}struct Msg *PutCom(int SonId,int Cmd,struct Msg *msg)//向服务端发送命令
{struct Msg *p=msg;send(SonId,(void *)p->com,strlen(p->com),0);//向服务端发送命令return p;
}struct Msg *GetBuf(int SonId,int Cmd,struct Msg *msg)//返回命名执行后的数据(返回服务端发送过来的的数据)
{FILE *fd=NULL;//用于打开文件用的文件描述符char str[50]={'\0'};//用于存储继续处理后的命令int len;//用于计算长度struct Msg *getdata=msg;//用于存储服务端发送回的数据memset(getdata->buf,0,sizeof(getdata->buf));switch(Cmd)//进入相关指令进行工作{case ls:case pwd://执行服务端shll指令{recv(SonId,(void *)getdata->buf,sizeof(getdata->buf),0);len=strlen(getdata->buf);}break;case cd://服务端跳转文件夹{recv(SonId,(void *)getdata->buf,sizeof(getdata->buf),0);len=strlen(getdata->buf);}break;case get://从服务器上下载文件到客户端{recv(SonId,(void *)getdata->buf,sizeof(getdata->buf),0);len=strlen(getdata->buf);if(!strcmp(getdata->buf,"error cmd")){break;}len=strlen(getdata->buf);strcpy(str,(getdata->com)+4);fd=fopen(str,"w+");if(fd==NULL){perror("fopen error");break; }fwrite((void *)(getdata->buf),sizeof(char),len,fd);fclose(fd);memset(getdata->buf,'\0',sizeof(getdata->buf));strcpy(getdata->buf,"get OK");}break;case put://将客户端文件上传到服务器{strcpy(str,(getdata->com)+4);len=strlen(str);fd=fopen(str,"r");if(fd==NULL){usleep(100);send(SonId,(void *)"error",strlen("error"),0);recv(SonId,(void *)getdata->buf,sizeof(getdata->buf),0);return getdata;}fseek(fd,0,SEEK_END);//将光标移动到文件流尾处len=ftell(fd);//取得文件流光标所在位置fseek(fd,0,SEEK_SET);fread(getdata->buf,sizeof(char),len,fd);len=strlen(getdata->buf);send(SonId,(void *)getdata->buf,len,0);fclose(fd);memset(getdata->buf,'\0',sizeof(getdata->buf));usleep(100);recv(SonId,(void *)getdata->buf,sizeof(getdata->buf),0);memset(getdata->buf,'\0',sizeof(getdata->buf));strcpy(getdata->buf,"put OK");}break;case lls://查看客户端当下目录{strcpy(getdata->buf,"/bin/ls");}break;case quit://客户端退出(子进程退出){strcpy(getdata->buf,"quit");}break;}return getdata;
}void ErrorReason(char *err,int count,int Errnum)//处理错误函数
{if(count==Errnum){perror(err);exit(-1);}return;
}
运行结果:运行服务端成功后,可接入多个客户端
读者可亲自实验ftp服务器开发的乐趣
作者:星辰~念
ftp服务器搭建类似云盘功能代码(带注释详解代码)相关推荐
- 史上最详细的Pytorch版yolov3代码中文注释详解(四)
史上最详细的Pytorch版yolov3代码中文注释详解(一):https://blog.csdn.net/qq_34199326/article/details/84072505 史上最详细的Pyt ...
- python3 上传文件到目标机器_Python3 +服务器搭建私人云盘,再也不怕限速了
先来看看效果 电脑访问 手机访问 Windows版本搭建 (1).首先你需要在你的电脑上或者服务器上安装Python3.X. (2).然后通过如下指令来安装updog库,网上有很多关于updog的介绍 ...
- 遗传算法(包含选择、交叉、变异) MATLAB完整代码 中文注释详解
该算法的选择.交叉.变异操作都采用了基础的方法,操作方法在代码的注释给出: 选择:二元锦标赛选择法: 交叉:单点交叉: 变异:单点变异 1.主程序 main clc;clearnVar = 100; ...
- 腾讯云服务器搭建NextCloud云盘
初衷 我相信每个人都想要创造一点个人的小空间,存放某种东西(你懂的). 为了达到这个目的,顺便学习一下服务器的搭建,折腾了几天,终于算是搞定了,便记录如下. 一 准备 思路:使用腾讯云服务器,部署LA ...
- 阿里云服务器搭建私人云盘seafile
cd进入根目录 执行下面的指令 yum install wget -y wget https://raw.githubusercontent.com/helloxz/seafile/master/in ...
- HTML简单入门 代码加注释详解
HTML 初识网页 <!DOCTYPE html> <html lang="en"> <!--head标签代表网页头部--> <head& ...
- 超简单!基于Python搭建个人“云盘”
1. 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码,而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类 ...
- 用python建云盘_实用的Python(3)超简单!基于Python搭建个人“云盘”
1 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码,而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类似 ...
- python自制个人网盘_超简单!基于Python搭建个人“云盘”
1 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码. 而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类 ...
最新文章
- “智能+”时代,看见别人看不见的才是赢家
- YYAsyncLayer 学习
- SDNU 1167.花生采摘(排序)
- 在VS.NET 的项目中使用生成事件
- 使用JDBC连接数据库(MySQL)的源代码
- 安卓学习笔记01:安装集成开发环境Android Studio
- 比亚迪汽车发布品牌全新标识 取消了椭圆型边界
- 英特尔:5G将释放云的潜力,为垂直行业带来巨大商机
- 小程序中 wx.navigateTo 页面跳转没有反应?
- SQL Server 2005 应用 全文搜索
- 易语言的Java皮肤_易语言软件更换皮肤的方法
- 将CSDN文章下载为markdown文档
- vue使用高德地图web端JSAPI 路线规划、搜索提示教程
- ps 自动生成html代码,ps怎么生成html网页文件 PS生成html网页文件的具体教程
- Docker部署Django由浅入深系列(中): 双容器部署Django + Uwsgi + Nginx
- Win10系统下Python安装和Geany环境配置的几点总结
- 正则表达式获取图片地址及超链接
- Excel的VLOOKUP函数及其用法
- 程序员遇到 Bug 时的 30 个反应,你是哪一种?
- 【读书笔记】《奇特的一生》