基于Linux的FTP文件传输项目(类似百度云)
项目功能
一、服务端
1.定义命令宏
2.命令转换
3.服务端的网络编程
4.实现LS,PWD功能
5.实现GET功能
6.实现PUT功能
7.实现CD,QUIT功能
二、客户端
1.实现LS,PWD,CD,GET功能
2.实现PUT功能
3.实现LLS,LCD,QUIT功能
4.打印服务端的数据
三.整体项目代码
一、服务端
1.定义命令宏
首先我们先创建一个config.h文件,用于存放我们将要输入的命令
#define LS 0
#define PWD 1
#define GET 2#define IFGO 3#define LLS 4
#define LCD 5
#define CD 6
#define PUT 7
#define QUIT 8
#define DOFILE 9struct Msg {int type;char data[1024]; //存放命令和文件数据char secondbuf[1024]; //存放文件内容
};
2.命令转换
定义一个函数将我们输入的命令转换为我们定义的宏
int get_cmd_type(char *cmd)
{/* strcmp(s1,s1)比较 s1 和 s2 若s1=s2,返回0*//*strstr(s1,s1)在字符串 s1 中查找第一次出现字符串 s2 的位置,未找到返回NULL*/if(strcmp(cmd, "ls") == 0) return LS;if(strcmp(cmd, "pwd") == 0) return PWD;if(strcmp(cmd, "quit") == 0) return QUIT;if(strstr(cmd, "get") != NULL) return GET;if(strstr(cmd, "put")!= NULL) return PUT;if(strstr(cmd, "cd")!= NULL) return CD;return 250;
}
3.服务端的网络编程
步骤:socket—bind—listen—while(1){accept—fork—while(1)—read—fun}—close
int main(int argc, char **argv)
{int ss_fd;int cc_fd;int n_read;struct Msg msg;struct sockaddr_in ss_addr;struct sockaddr_in cc_addr;if(argc != 3 ){printf("Input params error!\n");exit(-1);}memset(&ss_addr, 0, sizeof(ss_addr));memset(&cc_addr, 0, sizeof(cc_addr));/* 1.socket创建网络套接字*/ss_fd = socket(AF_INET, SOCK_STREAM, 0);if(ss_fd == -1){perror("socket error!");exit(-1);}/* 2.bind设置IP地址和端口号*/ss_addr.sin_family = AF_INET; //网络协议设置为IPV4ss_addr.sin_port = htons(atoi(argv[2])); //传递端口号, htons:从主机(小端)到网络(大端)inet_aton(argv[1], &ss_addr.sin_addr); //传递IP地址int ret = bind(ss_fd,(struct sockaddr *)&ss_addr, sizeof(struct sockaddr_in));if(ret == -1){perror("bind error!");exit(-1);}/* 3.listen*/listen(ss_fd, 5);/* 4.accept监听客户端请求*/int clen = sizeof(struct sockaddr_in);while(1) {cc_fd = accept(ss_fd, (struct sockaddr *)&cc_addr, &clen);if(cc_fd ==-1 ){perror("accept error!");exit(-1);}printf("get accept: %s\n", inet_ntoa(ss_addr.sin_addr)); //网络字节写转换为字符串形式,打印出IP地址/* 5.创建子进程*/if(fork() == 0){while(1){/* 清空msg当中的数据*/memset(&msg.data, 0, sizeof(msg.data));/* 1.读取cc_fd当中的数据到msg*/n_read = read(cc_fd, &msg, sizeof(msg));printf("n_read: %d\n", n_read);if(n_read == 0){printf("client out!\n");exit(-1);}/* 2.将调用msg_handler函数处理msg当中的命令数据*/if(n_read > 0){msg_handler(msg, cc_fd);}}}}return 0;
}
4.实现LS,PWD功能
当客户端输入“ls”,“pwd”指令时,需要将服务端的文件和路径显示在客户端上,那么在这里我们可以调用popen函数,该函数的功能是执行对应指令(ls,pwd),然后将结果值返回,最后可以用fread将返回值读取出来,代码如下:
case LS:
case PWD: /* 使用popen调用命令,将输出的结果存放到p中* 再使用fread,读取p中的内容*/p = popen(msg.data, "r");fread(msg.data, sizeof(msg.data), 1, p);write(cc_fd, &msg, sizeof(msg));
5.实现GET功能
当客户端输入“get”时,要获取服务端上某个文件的内容,即将服务端的文件复制到客户端上。类似于“cp”指令。代码如下:
case GET: /* 1.获取命令需要操作的文件名*/filename = getDesDir(msg.data);/* 2.判断文件是否存在*/if(access(filename,F_OK) == -1){// printf("NO This file!\n");strcpy(msg.data,"NO This file!");write(cc_fd, &msg, sizeof(msg));}/* 3.open文件,read文件, write文件内容到cc_fd当中*/else{msg.type = DOFILE;fdfile = open(filename, O_RDWR);read(fdfile, databuf, sizeof(databuf));strcpy(msg.data,databuf);write(cc_fd, &msg, sizeof(msg));close(fdfile);}break;
比如输入“get pro.c”首先要判断获取的pro.c文件是否存在,这里就需要先创建一个能获取文件名的函数getDesDir,若文件存在,将文件中的内存写入管道中。 getDesDir代码如下:
char *getDesDir(char *data)
{char *p;p = strtok(data," ");p = strtok(NULL," ");return p;
}
6.实现PUT功能
将客户端的文件复制到服务端上。首先调用getDesDir获取文件名,然后open创建并赋予权限,然后向文件写入内容。代码如下:
case PUT: /* 1.创建目标文件*/filename = getDesDir(msg.data);fdfile = open(filename, O_RDWR | O_CREAT, 0666);/* 2.将内容写进目标文件*/write(fdfile, msg.secondbuf, strlen(msg.secondbuf));close(fdfile);break;
7.实现CD,QUIT功能
case CD: /* 1.获取文件名*/filename = getDesDir(msg.data);/* 2.改变目录*/chdir(filename);break;case QUIT:printf("client quit\n");exit(-1); break;
二、客户端
客户端实现的逻辑与服务端大同小异
1.实现LS,PWD,CD,GET功能
这4个指令在客户端的内容都一样,只需发送指令即可
case LS:case PWD:case CD:case GET:write(cc_fd, &msg, sizeof(msg));break;
2.实现PUT功能
首先判断需要PUT的文件是否存在,然后open,read,write,close文件即可。
case PUT:/* 1.提取目标文件名*/filename = getfilename(msg.data);/* 2.判断目标文件是否存在*/if(access(filename, F_OK) == -1){printf("NO This File!\n"); }else{/* 3.传输文件内容,open, read, write,close*/fdfile = open(filename, O_RDWR);read(fdfile, msg.secondbuf, sizeof(msg.secondbuf));write(cc_fd, &msg, sizeof(msg));close(fdfile);}break;
3.实现LLS,LCD,QUIT功能
case LLS:system("ls");break;case LCD:/* 1.提取目标文件名*/filename = getfilename(msg.data);if(access(filename, F_OK) == -1){printf("NO This File!\n"); }else{/* 2.chdir*/chdir(filename);}break;case QUIT:write(cc_fd, &msg, sizeof(msg));close(cc_fd);exit(-1);break;
4.打印服务端的数据
1.将管道中的数据读到struct Msg结构体当中
2.GET命令比较特殊,相当于cp指令,需要open创建一个新文件,然后将数据写入到新文件当中
3.打印管道中的数据
具体功能实现代码如下:
void cmd_server_message(struct Msg msg, int cc_fd)
{int n_read;char *filename;int newfilefd;struct Msg msgget;/* 将管道中的数据读到结构体msgget中*/n_read = read(cc_fd, &msgget, sizeof(msgget));if(n_read == -1) {perror("read error!\n");;exit(-1);}if(msgget.type == DOFILE){/* 1.获取文件名*/filename = getfilename(msg.data);/* 2.创建文件*/newfilefd = open(filename, O_RDWR | O_CREAT ,0600);/* 3.将内容写入文件*/write(newfilefd, msgget.data, strlen(msgget.data));close(newfilefd);fflush(stdout);}else{/* 输出管道中的数据*/printf("------------------------\n");printf("%s\n",msgget.data);printf("------------------------\n");fflush(stdout);}}```三.整体项目代码
服务端——Server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include “config.h”
int get_cmd_type(char cmd)
{
/ strcmp(s1,s1)比较 s1 和 s2
若s1=s2,返回0*/
/*strstr(s1,s1)在字符串 s1 中
查找第一次出现字符串 s2 的位置,未找到返回NULL*/if(strcmp(cmd, "ls") == 0) return LS;
if(strcmp(cmd, "pwd") == 0) return PWD;
if(strcmp(cmd, "quit") == 0) return QUIT;if(strstr(cmd, "get") != NULL) return GET;
if(strstr(cmd, "put")!= NULL) return PUT;
if(strstr(cmd, "cd")!= NULL) return CD;return 250;
}
char *getDesDir(char *data)
{
char *p;
p = strtok(data," “);
p = strtok(NULL,” ");
return p;
}
void msg_handler(struct Msg msg, int cc_fd)
{
int ret;
int fdfile;
char *filename;
FILE *p;
char databuf[1024] = {0};
/* 1.获取命令msg.data,并将数据转换为int整数类型*/
ret = get_cmd_type(msg.data);
printf("cmd: %s\n", msg.data);
printf("ret: %d\n", ret);/* 2.调用switch处理命令*/
switch(ret) { case LS: case PWD: /* 使用popen调用命令,将输出的结果存放到p中* 再使用fread,读取p中的内容*/p = popen(msg.data, "r");fread(msg.data, sizeof(msg.data), 1, p);write(cc_fd, &msg, sizeof(msg));break;case GET: /* 1.获取命令需要操作的文件名*/filename = getDesDir(msg.data);/* 2.判断文件是否存在*/if(access(filename,F_OK) == -1){// printf("NO This file!\n");strcpy(msg.data,"NO This file!");write(cc_fd, &msg, sizeof(msg));}/* 3.open文件,read文件, write文件内容到cc_fd当中*/else{msg.type = DOFILE;fdfile = open(filename, O_RDWR);read(fdfile, databuf, sizeof(databuf));strcpy(msg.data,databuf);write(cc_fd, &msg, sizeof(msg));close(fdfile);}break;case PUT: /* 1.创建目标文件*/filename = getDesDir(msg.data);fdfile = open(filename, O_RDWR | O_CREAT, 0666);/* 2.将内容写进目标文件*/write(fdfile, msg.secondbuf, strlen(msg.secondbuf));close(fdfile);break;case CD: /* 1.获取文件名*/filename = getDesDir(msg.data);/* 2.改变目录*/chdir(filename);break;case QUIT:printf("client quit\n");exit(-1); break;}
// printf(“sssssssssss\n”);
}
int main(int argc, char **argv)
{
int ss_fd;
int cc_fd;
int n_read;
struct Msg msg;
struct sockaddr_in ss_addr;
struct sockaddr_in cc_addr;
if(argc != 3 ){printf("Input params error!\n");exit(-1);
}memset(&ss_addr, 0, sizeof(ss_addr));
memset(&cc_addr, 0, sizeof(cc_addr));
/* 1.socket创建网络套接字*/
ss_fd = socket(AF_INET, SOCK_STREAM, 0);
if(ss_fd == -1){perror("socket error!");exit(-1);
}
/* 2.bind设置IP地址和端口号*/
ss_addr.sin_family = AF_INET; //网络协议设置为IPV4
ss_addr.sin_port = htons(atoi(argv[2])); //传递端口号, htons:从主机(小端)到网络(大端)
inet_aton(argv[1], &ss_addr.sin_addr); //传递IP地址int ret = bind(ss_fd,(struct sockaddr *)&ss_addr, sizeof(struct sockaddr_in));
if(ret == -1){perror("bind error!");exit(-1);
}
/* 3.listen*/
listen(ss_fd, 5);
/* 4.accept监听客户端请求*/
int clen = sizeof(struct sockaddr_in);
while(1) {cc_fd = accept(ss_fd, (struct sockaddr *)&cc_addr, &clen);if(cc_fd ==-1 ){perror("accept error!");exit(-1);}printf("get accept: %s\n", inet_ntoa(ss_addr.sin_addr)); //网络字节写转换为字符串形式,打印出IP地址/* 5.创建子进程*/if(fork() == 0){while(1){/* 清空msg当中的数据*/memset(&msg.data, 0, sizeof(msg.data));/* 1.读取cc_fd当中的数据到msg*/n_read = read(cc_fd, &msg, sizeof(msg));printf("n_read: %d\n", n_read);if(n_read == 0){printf("client out!\n");exit(-1);}/* 2.将调用msg_handler函数处理msg当中的命令数据*/if(n_read > 0){msg_handler(msg, cc_fd);}}}
}
return 0;
}
客户端——Client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include “config.h”
int cmd_int(char cmd)
{
/ strcmp(s1,s1)比较 s1 和 s2
若s1=s2,返回0*/
/*strstr(s1,s1)在字符串 s1 中
查找第一次出现字符串 s2 的位置,未找到返回NULL*/if(strcmp(cmd, "ls") == 0) return LS;
if(strcmp(cmd, "lls") == 0) return LLS;
if(strcmp(cmd, "pwd") == 0) return PWD;
if(strcmp(cmd, "quit") == 0) return QUIT;if(strstr(cmd, "get") != NULL) return GET;
if(strstr(cmd, "put")!= NULL) return PUT;
if(strstr(cmd, "cd")!= NULL) return CD;
if(strstr(cmd, "lcd")!= NULL) return LCD;
return -1;
}
char *getfilename(char *str)
{
char *filename;
filename = strtok(str, " ");
filename = strtok(NULL, " ");
return filename;
}
int cmd_handler(struct Msg msg, int cc_fd)
{
int ret;
char filename;
int fdfile;
/ 1.将字符串指令,转换为int整数类型*/
ret = cmd_int(msg.data);
printf(“ret: %d\n”, ret);
/* 2.调用switch处理ret*/
switch(ret) {case LS:case PWD:case CD:case GET:write(cc_fd, &msg, sizeof(msg));break;case PUT:/* 1.提取目标文件名*/filename = getfilename(msg.data);/* 2.判断目标文件是否存在*/if(access(filename, F_OK) == -1){printf("NO This File!\n"); }else{/* 3.传输文件内容,open, read, write,close*/fdfile = open(filename, O_RDWR);read(fdfile, msg.secondbuf, sizeof(msg.secondbuf));write(cc_fd, &msg, sizeof(msg));close(fdfile);}break;case LLS:system("ls");break;case LCD:/* 1.提取目标文件名*/filename = getfilename(msg.data);if(access(filename, F_OK) == -1){printf("NO This File!\n"); }else{/* 2.chdir*/chdir(filename);}break;case QUIT:write(cc_fd, &msg, sizeof(msg));close(cc_fd);exit(-1);break;
}return ret;
}
void cmd_server_message(struct Msg msg, int cc_fd)
{
int n_read;
char *filename;
int newfilefd;
struct Msg msgget;
/* 将管道中的数据读到结构体msgget中*/
n_read = read(cc_fd, &msgget, sizeof(msgget));if(n_read == -1) {perror("read error!\n");;exit(-1);
}if(msgget.type == DOFILE){/* 1.获取文件名*/filename = getfilename(msg.data);/* 2.创建文件*/newfilefd = open(filename, O_RDWR | O_CREAT ,0600);/* 3.将内容写入文件*/write(newfilefd, msgget.data, strlen(msgget.data));close(newfilefd);fflush(stdout);
}else{/* 输出管道中的数据*/printf("------------------------\n");printf("%s\n",msgget.data);printf("------------------------\n");fflush(stdout);
}
}
int main(int argc, char **argv)
{
int cc_fd;
int con;
int ret;
struct Msg msg;
struct sockaddr_in cc_addr;
if(argc != 3){printf("Input params error!\n");exit(-1);
}
/* 1.socket调用套接字*/
cc_fd = socket(AF_INET, SOCK_STREAM, 0);
if(cc_fd == -1) {perror("socket error");exit(-1);
}
//int connect(int sockfd, const struct sockaddr addr,
// socklen_t addrlen);
/ 2.connect请求链接到服务端*/
cc_addr.sin_family = AF_INET; //网络协议设置为IPV4
cc_addr.sin_port = htons(atoi(argv[2])); //传递端口号, htons:从主机(小端)到网络(大端)
inet_aton(argv[1], &cc_addr.sin_addr); //传递IP地址
con = connect(cc_fd, (struct sockaddr *)&cc_addr, sizeof(struct sockaddr_in));
if(con == -1) {perror("connect error");exit(-1);
}
printf("connect ...\n");while(1) {/* 1.刷新msg.data*/memset(&msg.data, 0, sizeof(msg.data));/* 2.获取输入指令,保存到msg.data*/gets(msg.data);/* 3.调用cmd_handler函数,将指令传入到cc_fd中*/ret = cmd_handler(msg, cc_fd);printf("mainret:%d\n",ret);/* 4.过滤指令*/if(ret > IFGO){continue; //跳出循环,不继续执行下面代码}if(ret == -1){printf("command error! Please enter again!\n");continue;}/* 5.输出指令产生的内容*/cmd_server_message(msg, cc_fd);
}return 0;
}
基于Linux的FTP文件传输项目(类似百度云)相关推荐
- Qt网络编程小项目-基于Tcp协议的文件传输项目
目录 项目描述 Qt下Tcp服务器端和客户端流程: 具体流程: 客户端: 服务器端: 源码: 服务器端: 服务器头文件: 服务器源文件: 服务器端ui 客户端: 客户端头文件: 客户端源文件: 客户端 ...
- FTP文件传输协议(实现windows与linux文件互传)
FTP文件传输协议(实现windows与linux文件互传) 目录 FTP文件传输协议(实现windows与linux文件互传) 一.FTP概述 二.FTP通信端口 三.FTP数据连接 四.FTP连接 ...
- Linux下基于TCP的简易文件传输(socket编程)
Linux下基于TCP的简易文件传输(socket编程) OSI和TCP/IP: 关于TCP/IP协议 关于TCP协议 TCP编程的一般步骤[^2] TCP文件传输实现 功能概述 服务器编程 客户端编 ...
- 基于python的文件传输程序_7个步骤,教你快速学会用python实现ftp文件传输功能(收藏了)...
文章主要为大家详细介绍了python实现ftp文件传输功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下!!! 本文实例为大家分享了python实现ftp文件传输的具体 ...
- linux做完sftp端口分离后ftp,Linux 中实现文件传输服务(FTP、SFTP)
????本文将介绍如何在Linux中实现文件传输,这里主要使用FTP.SFTP. ????FTP ????废话少说,直接进入正题,需要注意,FTP采用Client/Server架构,并且有两个信道(控 ...
- Linux 网络服务之FTP 文件传输
Linux FTP 文件传输 --王宇然qq:496488051 实验一:配置匿名上传FTP 1.软件包安装: [root@localhost ~]# cd /misc/cd/Server ...
- put与mput_常用的ftp文件传输命令为:bin、asc、put、get、mput、mget、prompt、bye。-智慧树Linux操作系统章节答案...
Linux操作系统:常用的ftp文件传输命令为:bin.asc.put.get.mput.mget.prompt.bye.[?????] A:错 B:对 Linux操作系统章节测试答案: 对 更多相关 ...
- Linux运维系列总结-Linux系统启动过程、WEB工作原理、DHCP工作原理、DNS解析原理、NFS网络文件系统、FTP文件传输协议、PXE+KICKSTART自动安装系统
Linux运维系列总结-Linux系统启动过程.WEB工作原理.DHCP工作原理.DNS解析原理.NFS网络文件系统.FTP文件传输协议.PXE+KICKSTART自动安装系统 1.Linux系统的启 ...
- Linux利用FTP服务传输文件(山有木兮木有枝,心悦君兮君不知)
文章目录 一.FTP协议 二.Linux系统配置FTP协议实现文件传输 实例1:匿名用户 实例2:本地用户访问 一.FTP协议 1.FTP协议简介 与大多数 Internet服务一样,FTP也是一个c ...
- 详解“FTP文件传输服务”安装配置实例
"FTP文件传输服务"安装配置实例 家住海边喜欢浪:zhang789.blog.51cto.com 目录 简介 ftp工作原理 常见的FTP服务 Vsftpd服务器的安装 Vsft ...
最新文章
- 瘫痪17年,利用双向脑机接口来诱发触觉,控制机械手
- 漫谈 Weblogic CVE-2020-2555
- Websocket总结
- 什么时候html的过渡版本,CSS过渡与转换
- github的一些简单用法
- asp.net 得到上一页地址
- 数据结构-Hash总结(二)
- 前端学习(1954)vue之电商管理系统电商系统之重置表单数据
- php能做什么程序,PHP 能做什么?
- android水印的添加,Android添加水印的正确方法 只要三步!
- Mac上通过docker配置PHP开发环境
- js刻度尺插件_html5 canvas+js刻度尺代码
- bh1750采集流程图_基于BH1750的光照度检测)报告方案.doc
- spring boot 整合 ip2region(ip地址库)
- 狂神学习系列04:MySQL+JDBC
- 测试工程师也应该具备产品化思维吗?
- iOS 局域网通讯 MultipeerConnectivity
- Thymeleaf模板(全程案例详解)
- Java基础——狂神说
- Spark提交报错:1 node(s) are excluded in this operation