自制FTP云盘项目
前言
本文是基于Linux网络编程实现的FTP服务器,服务器由服务端和客户端组成,具有浏览远程服务端的文件和浏览客户端本地文件,同时支持对远程服务端文件的删除,存储,归档操作处理,以及客户端对远程服务端文件的上传和下载。
一、程序简介
FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。 FTP是File Transfer Protocol(文件传输协议)。
程序运行,服务端不断接收客户端指令,服务端可同时处理多个客户端接入并对指令作出解析,并把执行结果返回给客户端,客户端根据服务端对指令的解析并把由服务端传递过来的处理信息通过客户端呈现给客户,实现文件的各种操作。
二、代码演示
1.主要使用的函数
整个服务器主要使用的函数:
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int access(const char *pathname, int mode);
2.指令配置文件
服务器指令配置如下:
#define LS 1
#define LLS 2
#define CD 3
#define LCD 4
#define GET 5
#define PUT 6
#define PWD 7
#define RM 8
#define MKDIR 9
#define QUIT 0
typedef struct msg //客户端和服务端传递信息的结构体
{
int type;
char cmd[128];
char data_buf[1024];
}Msg,*P_msg;
3.服务端
服务端代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config.h"
int command_hundler(char *r_buf)
{
if(strcmp(r_buf,"ls") == 0) return LS;
if(strcmp(r_buf, "lls") == 0) return LLS;
if(strstr(r_buf, "cd") != NULL && strstr(r_buf, "lcd") == NULL) return CD;
if(strstr(r_buf, "lcd") != NULL) return LCD;
if(strstr(r_buf, "get") != NULL) return GET;
if(strstr(r_buf, "put") != NULL) return PUT;
if(strcmp(r_buf, "pwd") == 0) return PWD;
if(strstr(r_buf, "rm") != NULL) return RM;
if(strstr(r_buf, "mkdir") != NULL) return MKDIR;
if(strcmp(r_buf, "quit") == 0) return QUIT;
return -1;
}
char *command_segmentation(char *cmd)
{
char *file_name = NULL;
file_name = strtok(cmd, " ");
file_name = strtok(NULL, " ");
return file_name;
}
int command(int *ac_fd)
{
int cmd = -1;
FILE *p_fd;
char *file_name = NULL;
char *cmd_buf = NULL;
Msg r_msg_buf;
Msg w_msg_buf;
memset(&r_msg_buf, 0, sizeof(Msg));
memset(&w_msg_buf, 0, sizeof(Msg));
read(*ac_fd, &r_msg_buf, sizeof(Msg));
cmd = command_hundler(r_msg_buf.cmd);
switch(cmd)
{
case LS:
w_msg_buf.type = LS;
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
p_fd = popen("ls -l", "r");
if(p_fd == NULL)
{
printf("popen error!\n");
exit(-1);
}
fread(w_msg_buf.data_buf, 1024, 1, p_fd);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
fclose(p_fd);
printf("===== ls =====\n");
break;
case LLS:
w_msg_buf.type = LLS;
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
printf("===== lls =====\n");
break;
case CD:
w_msg_buf.type = CD;
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
file_name = command_segmentation(r_msg_buf.cmd);
//int chdir(const char *path);
if(access(file_name, F_OK) == 0)
{
chdir(file_name);
strcpy(w_msg_buf.data_buf, file_name);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
}
else
{
strcpy(w_msg_buf.data_buf, "The server is no such file directory!");
write(*ac_fd, &w_msg_buf, sizeof(Msg));
}
printf("===== cd =====\n");
break;
case LCD:
w_msg_buf.type = LCD;
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
strcpy(w_msg_buf.data_buf, r_msg_buf.cmd);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
printf("===== lcd =====\n");
break;
case GET:
w_msg_buf.type = GET;
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
file_name = command_segmentation(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(*ac_fd, &w_msg_buf, sizeof(Msg));
close(fd);
}
else
{
strcpy(w_msg_buf.data_buf, "The server is no such document!");
write(*ac_fd, &w_msg_buf, sizeof(Msg));
}
printf("===== get =====\n");
break;
case PUT:
read(*ac_fd, &r_msg_buf, sizeof(Msg));
file_name = command_segmentation(r_msg_buf.cmd);
if(strcmp(r_msg_buf.data_buf, "The client is no such document!") != 0)
{
if(access(file_name, F_OK) == 0)
{
int fd = open(file_name, O_RDWR|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("===== put =====\n");
break;
case PWD:
w_msg_buf.type = PWD;
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
p_fd = popen("pwd", "r");
if(p_fd == NULL)
{
printf("popen error!\n");
exit(-1);
}
fread(w_msg_buf.data_buf, 1024, 1, p_fd);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
printf("===== pwd =====\n");
break;
case RM:
cmd_buf = (char *)malloc(128);
memset(cmd_buf, 0, 128);
file_name = command_segmentation(r_msg_buf.cmd);
sprintf(cmd_buf, "rm -r %s", file_name);
if(access(file_name, F_OK) != 0)
{
sprintf(w_msg_buf.data_buf, "File %s does not exist!", file_name);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
}
else
{
system(cmd_buf);
free(cmd_buf);
cmd_buf = NULL;
sprintf(w_msg_buf.data_buf, "File %s has been deleted!", file_name);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
}
printf("===== rm =====\n");
break;
case MKDIR:
w_msg_buf.type = MKDIR;
cmd_buf = (char *)malloc(128);
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
file_name = command_segmentation(r_msg_buf.cmd);
sprintf(cmd_buf, "mkdir %s", file_name);
if(access(file_name, F_OK) == 0)
{
sprintf(w_msg_buf.data_buf, "File %s already exists!", file_name);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
}
else
{
system(cmd_buf);
free(cmd_buf);
cmd_buf = NULL;
sprintf(w_msg_buf.data_buf, "File %s has been created!", file_name);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
}
printf("===== mkdir =====\n");
break;
case QUIT:
w_msg_buf.type = QUIT;
strcpy(w_msg_buf.cmd, r_msg_buf.cmd);
strcpy(w_msg_buf.data_buf, r_msg_buf.cmd);
write(*ac_fd, &w_msg_buf, sizeof(Msg));
printf("=====client exit=====\n");
close(*ac_fd);
exit(0);
break;
case -1:
strcpy(w_msg_buf.data_buf, "Command error!");
write(*ac_fd, &w_msg_buf, sizeof(Msg));
printf("===== cmd error =====\n");
break;
}
memset(&r_msg_buf, 0, sizeof(Msg));
memset(&w_msg_buf, 0, sizeof(Msg));
return 0;
}
int main(int argc, char **argv)
{
if(argc != 3)
{
printf("argument is too few!");
return -1;
}
int s_fd;
int ac_fd;
int i;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
char r_buf[20] = {'\0'};
char w_buf[20] = {'\0'};
strcpy(w_buf, "i am here!");
int len = sizeof(struct sockaddr_in);
memset(&s_addr, 0, sizeof(struct sockaddr_in));
memset(&c_addr, '\0', sizeof(struct sockaddr_in));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1], &s_addr.sin_addr);
s_fd = socket(AF_INET, SOCK_STREAM, 0);
if(s_fd == -1)
{
perror("socket error:");
exit(-1);
}
if(bind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in)) == -1)
{
perror("bind error:");
exit(-1);
}
if(listen(s_fd, 10) == -1)
{
perror("listen error:");
exit(-1);
}
for(i = 0; i < 10; i++)
{
ac_fd = accept(s_fd, (struct sockaddr *)&c_addr, &len);
if(ac_fd == -1)
{
perror("accept error:");
exit(-1);
}
if(fork() == 0)
{
printf("The client is connected!\n");
while(1)
{
command(&ac_fd);
}
}
}
close(s_fd);
return 0;
}
服务器可以同时接收10个客户端的连接,accept()返回一个套接字连接,并使用一个fork()函数开启一个子进程并管理一个客户端的连接。客户端连接进来以后,调用函数解析由客户端传递过来的指令,并返回对应指令的宏定义,进入对应命令处理指令,并把处理结果返回给客户端。客户端对服务端文件的操作需要注意的是验证文件存在。
4.客户端
其中客户端做的操作是接受用户输入的指令,并把指令传递给远程服务端,等待服务端处理完对文件的操作的时候,把服务端指令处理结果以文字的方式打印在客户端界面呈现给用户。
服务端代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>
int command_hundler(char *r_buf)
{
if(strcmp(r_buf,"ls") == 0) return LS;
if(strcmp(r_buf, "lls") == 0) return LLS;
if(strstr(r_buf, "cd") != NULL && strstr(r_buf, "lcd") == NULL) return CD;
if(strstr(r_buf, "lcd") != NULL) return LCD;
if(strstr(r_buf, "get") != NULL) return GET;
if(strstr(r_buf, "put") != NULL) return PUT;
if(strcmp(r_buf, "pwd") == 0) return PWD;
if(strstr(r_buf, "rm") != NULL) return RM;
if(strstr(r_buf, "mkdir") != NULL) return MKDIR;
if(strcmp(r_buf, "quit") == 0) return QUIT;
return -1;
}
char *command_segmentation(char *cmd)
{
char *file_name = NULL;
file_name = strtok(cmd, " ");
file_name = strtok(NULL, " ");
return file_name;
}
int command(int *s_fd)
{
int cmd;
FILE *p_fd;
int fd;
char *file_name = NULL;
Msg r_msg_buf;
Msg w_msg_buf;
char w_msg_buf_cp[128] = {0};
memset(&r_msg_buf, 0, sizeof(Msg));
memset(&w_msg_buf, 0, sizeof(Msg));
printf(">");
gets(w_msg_buf.cmd);
write(*s_fd, &w_msg_buf, sizeof(Msg)); //send msg to server
cmd = command_hundler(w_msg_buf.cmd);
printf("************************************************************************************\n");
printf("\n");
switch(cmd)
{
case LS:
read(*s_fd, &r_msg_buf, sizeof(Msg));
printf("%s\n", r_msg_buf.data_buf);
break;
case LLS:
read(*s_fd, &r_msg_buf, sizeof(Msg));
p_fd = popen("ls -l", "r");
memset(r_msg_buf.data_buf, 0, 1024);
fread(r_msg_buf.data_buf, 1024, 1, p_fd);
printf("%s\n", r_msg_buf.data_buf);
fclose(p_fd);
break;
case CD:
read(*s_fd, &r_msg_buf, sizeof(Msg));
if(strcmp(r_msg_buf.data_buf, "The server is no such file directory!") == 0)
{
printf("%s\n", r_msg_buf.data_buf);
}
break;
case LCD:
read(*s_fd, &r_msg_buf, sizeof(Msg));
file_name = command_segmentation(r_msg_buf.cmd);
if(access(file_name, F_OK) == 0)
{
chdir(file_name);
}
else
{
memset(r_msg_buf.data_buf, 0, 1024);
strcpy(r_msg_buf.data_buf, "The client is no such file directory!");
printf("%s\n", r_msg_buf.data_buf);
}
break;
case GET:
read(*s_fd, &r_msg_buf,sizeof(Msg));
file_name = command_segmentation(r_msg_buf.cmd);
if(strcmp(r_msg_buf.data_buf, "The server is no such 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);
if(fd == -1)
{
perror("open error: ");
}
if(write(fd, r_msg_buf.data_buf, strlen(r_msg_buf.data_buf)) == -1)
{
perror("write error: ");
}
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("File %s was downloaded successfully!\n", file_name);
putchar('\n');
break;
case PUT:
w_msg_buf.type = PUT;
strcpy(w_msg_buf_cp, w_msg_buf.cmd);
file_name = command_segmentation(w_msg_buf_cp);
if(access(file_name, F_OK) == 0)
{
int fd = open(file_name, O_RDWR);
read(fd, w_msg_buf.data_buf, 1024);
write(*s_fd, &w_msg_buf, sizeof(Msg));
close(fd);
}
else
{
strcpy(w_msg_buf.data_buf, "The client is no such document!");
write(*s_fd, &w_msg_buf, sizeof(Msg));
printf("%s\n", w_msg_buf.data_buf);
}
printf("File %s has been uploaded successfully!\n", file_name);
putchar('\n');
break;
case PWD:
read(*s_fd, &r_msg_buf, sizeof(Msg));
printf("%s\n", r_msg_buf.data_buf);
break;
case RM:
read(*s_fd, &r_msg_buf, sizeof(Msg));
printf("%s\n", r_msg_buf.data_buf);
printf("\n");
break;
case MKDIR:
read(*s_fd, &r_msg_buf, sizeof(Msg));
printf("%s\n", r_msg_buf.data_buf);
printf("\n");
break;
case QUIT:
read(*s_fd, &r_msg_buf, sizeof(Msg));
printf("************************************************************************************\n");
exit(0);
break;
default :
read(*s_fd, &r_msg_buf, sizeof(Msg));
printf("%s\n", r_msg_buf.data_buf);
putchar('\n');
break;
}
memset(&r_msg_buf, 0, sizeof(Msg));
memset(&w_msg_buf, 0, sizeof(Msg));
printf("************************************************************************************\n");
return 0;
}
int main(int argc, char **argv)
{
int s_fd;
char r_buf[20] = {'\0'};
char w_buf[20] = {'\0'};
strcpy(w_buf, "i am client!");
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof(struct sockaddr_in));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1], &s_addr.sin_addr);
s_fd = socket(AF_INET, SOCK_STREAM, 0);
if(s_fd == -1)
{
perror("socket error:");
exit(-1);
}
if(connect(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in)) == -1)
{
perror("connect error:");
exit(-1);
}
while(1)
{
command(&s_fd);
}
close(s_fd);
return 0;
}
三、服务器运行演示
服务器运行演示视频:https://www.bilibili.com/video/BV1Vr4y1M7Ar
总结
以上是自己的在网络编程这块的学习心得,希望可以和更多优秀的大神一起学习交流,自己有何不足之处还望各位大神不吝赐教。