ftp服务器使用说明

  1. 运行服务端
    ./server 本机IP地址 端口号(使用ifconfig查看本机IP 地址)

  2. 运行客户端 ./client 服务器IP地址 相同端口号

运行成功后可执行以下指令,实现类似云盘功能

指令说明

  1. ls —— 查看服务端当下目录
  2. lls —— 查看客户端当下目录
  3. pwd —— 查看服务端当前路径
  4. quit —— 客户端退出连接
  5. cd name —— 令服务器进入到name路径下下
  6. get name —— 从服务器上下载name文件
  7. 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服务器搭建类似云盘功能代码(带注释详解代码)相关推荐

  1. 史上最详细的Pytorch版yolov3代码中文注释详解(四)

    史上最详细的Pytorch版yolov3代码中文注释详解(一):https://blog.csdn.net/qq_34199326/article/details/84072505 史上最详细的Pyt ...

  2. python3 上传文件到目标机器_Python3 +服务器搭建私人云盘,再也不怕限速了

    先来看看效果 电脑访问 手机访问 Windows版本搭建 (1).首先你需要在你的电脑上或者服务器上安装Python3.X. (2).然后通过如下指令来安装updog库,网上有很多关于updog的介绍 ...

  3. 遗传算法(包含选择、交叉、变异) MATLAB完整代码 中文注释详解

    该算法的选择.交叉.变异操作都采用了基础的方法,操作方法在代码的注释给出: 选择:二元锦标赛选择法: 交叉:单点交叉: 变异:单点变异 1.主程序 main clc;clearnVar = 100; ...

  4. 腾讯云服务器搭建NextCloud云盘

    初衷 我相信每个人都想要创造一点个人的小空间,存放某种东西(你懂的). 为了达到这个目的,顺便学习一下服务器的搭建,折腾了几天,终于算是搞定了,便记录如下. 一 准备 思路:使用腾讯云服务器,部署LA ...

  5. 阿里云服务器搭建私人云盘seafile

    cd进入根目录 执行下面的指令 yum install wget -y wget https://raw.githubusercontent.com/helloxz/seafile/master/in ...

  6. HTML简单入门 代码加注释详解

    HTML 初识网页 <!DOCTYPE html> <html lang="en"> <!--head标签代表网页头部--> <head& ...

  7. 超简单!基于Python搭建个人“云盘”

    1. 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码,而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类 ...

  8. 用python建云盘_实用的Python(3)超简单!基于Python搭建个人“云盘”

    1 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码,而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类似 ...

  9. python自制个人网盘_超简单!基于Python搭建个人“云盘”

    1 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码. 而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类 ...

最新文章

  1. “智能+”时代,看见别人看不见的才是赢家
  2. YYAsyncLayer 学习
  3. SDNU 1167.花生采摘(排序)
  4. 在VS.NET 的项目中使用生成事件
  5. 使用JDBC连接数据库(MySQL)的源代码
  6. 安卓学习笔记01:安装集成开发环境Android Studio
  7. 比亚迪汽车发布品牌全新标识 取消了椭圆型边界
  8. 英特尔:5G将释放云的潜力,为垂直行业带来巨大商机
  9. 小程序中 wx.navigateTo 页面跳转没有反应?
  10. SQL Server 2005 应用 全文搜索
  11. 易语言的Java皮肤_易语言软件更换皮肤的方法
  12. 将CSDN文章下载为markdown文档
  13. vue使用高德地图web端JSAPI 路线规划、搜索提示教程
  14. ps 自动生成html代码,ps怎么生成html网页文件 PS生成html网页文件的具体教程
  15. Docker部署Django由浅入深系列(中): 双容器部署Django + Uwsgi + Nginx
  16. Win10系统下Python安装和Geany环境配置的几点总结
  17. 正则表达式获取图片地址及超链接
  18. Excel的VLOOKUP函数及其用法
  19. 程序员遇到 Bug 时的 30 个反应,你是哪一种?
  20. 【读书笔记】《奇特的一生》

热门文章

  1. ssm学校图书资源交易平台计算机毕业设计
  2. Socket编程服务器和客户端【重要】
  3. 店铺有点击没有转化怎么办
  4. c#使用委托事件实现信用卡定期还款功能
  5. Twincat3搭建
  6. Hadoop的mapreduce的执行过程
  7. 电子出版阅读战 当当亚马逊对决BAT
  8. Matlab编程技巧:导入A2L文件
  9. Linux库概念及相关编程
  10. Github推荐:超好用的全开源协同OA项目