Implementation of FTP cloud disk for linux small project
preface
In the past two days, I have reviewed the basic knowledge of linux (file IO operation, process, thread, network programming, interprocess communication) I learned before. Well, on the whole, I have a deeper understanding of the knowledge points than I learned for the first time. I also have my own understanding of many ambiguous concepts before. As the saying goes: "review the old and know the new, you can be a teacher." what the ancients said is very reasonable.
For my personal study, I may not be very smart, but I also believe that diligence can make up for weakness, so I am willing to take time to review the previously learned knowledge points again and again, and demonstrate the learned knowledge points through small experiments one after another. This learning method is very effective for me personally, and I really feel my continuous progress.
For programming learning, it's really impossible to want to become stronger just by watching videos. We can only constantly knock code, constantly make bugs, and constantly take time to solve them. Finally, we can constantly summarize knowledge points, so that we can continue to grow on the road of programming. I feel very confident in learning new knowledge. Generally speaking, I am quite self disciplined and have clear plans and goals. Well, in short, I should take a small step forward every day. Come on. (Xiao Yin, who has been struggling all the time)
Well, FTP cloud disk is a small project. The server and client add up to about 500 lines of code. Of course, many details may not be handled, but the function is probably realized. There are still some small problems when downloading and uploading files with get xxx and put xxx, but we can get the content we want, which will be optimized later.
Tip: the following is the main content of this article. The following cases can be used for reference
1, Server implementation
/*********************************FTP-Server************************************ *Realize the message sending between the client and the server (the server only accepts the processing instructions) *Date:2022-2-25 *Author:Xiao Yin *Version:1.0 *******************************************************************************/ #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <sys/stat.h> //Command macro definition #define LS 1 #define CD 2 #define PWD 3 #define LCD 4 #define LLS 5 #define GET 6 #define PUT 7 #define QUIT 8 #define DOFILE 9 #define MAX_ Listen at the same time struct FTP { int type; //type char databuf[1024]; //data char buf[1024]; //data char cmd[24]; //command }; struct FTP msg; int Get_CMD(char *cmd); //Command acquisition void MSG_Handler(struct FTP msg,int fd);//information processing int main(int argc,char *argv[]) { int s_fd = 0,c_fd = 0; int addr_len = 0; int n_read = 0; struct sockaddr_in s_addr,c_addr; //1. Create socket //int socket(int domain, int type, int protocol); s_fd = socket(AF_INET,SOCK_STREAM,0); if(s_fd == 0) { printf("socket error\n"); exit(-1); } //empty //void *memset(void *s, int c, size_t n); memset(&s_addr,'0',sizeof(struct sockaddr_in)); memset(&c_addr,'0',sizeof(struct sockaddr_in)); s_addr.sin_family = AF_INET; //uint16_t htons(uint16_t hostshort); //int atoi(const char *nptr); s_addr.sin_port = htons(atoi(argv[2])); //Port number conversion //int inet_aton(const char *cp, struct in_addr *inp); inet_aton(argv[1],&s_addr.sin_addr); //IP address //2. Binding // int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); if(bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in)) == -1) { printf("bind error\n"); exit(-1); } //3. Monitoring //int listen(int sockfd, int backlog); if(listen(s_fd,MAX_LISTEN) == -1) { printf("listen error\n"); exit(-1); } addr_len = sizeof(struct sockaddr_in); while(1) { //4. Acceptance static int i = 0; //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&addr_len); if(c_fd == -1) { printf("accept error\n"); exit(-1); } i++; //char *inet_ntoa(struct in_addr in); //If the connection is successful, print the ip and port of each connection printf("connect success No %d client ip:%s port:%d\n",i,inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port)); //5. Reading and writing if(fork() == 0) { while(1) { printf("--------------------------wait cmd----------------------\n"); n_read = read(c_fd,msg.cmd,sizeof(msg.cmd)); if(n_read > 0) { MSG_Handler(msg,c_fd); } else if(n_read == 0) { printf("Client had quit connect\n"); exit(0); } else { printf("read error\n"); exit(-1); } } } } //6. Close close(c_fd); close(s_fd); return 0; } /*---------------------------------------Related function--------------------------------*/ //Get command int get_cmd_type(char *cmd ) { if(!strcmp("ls",cmd)) return LS; if(!strcmp("quit",cmd)) return QUIT; if(!strcmp("pwd",cmd)) return PWD; if(strstr(cmd,"cd") != NULL) return CD; if(strstr(cmd,"get") != NULL) return GET; if(strstr(cmd,"put") != NULL) return PUT; return 100; } //Get delimited file char *getDesDir(char *str) { char *p; p = strtok(str," "); //str the strings to be separated are separated by spaces p = strtok(NULL," "); //The second time, NULL is used as str printf("p is <%s>\n",p); //Print acquired files return p; } //The server obtains the command and processes and parses it void MSG_Handler(struct FTP msg,int fd) { int ret = 0; FILE *fp = NULL; char *file = NULL; //get files int ffile = 0; //File open return descriptor int len = 0; //Calculate file length char buf[1024] = {0}; //Cache content char *p = NULL; //Get command ret = get_cmd_type(msg.cmd); printf("Get cmd = %d\n",ret); switch(ret) { case LS: case PWD: //FILE *popen(const char *command, const char *type); fp = popen(msg.cmd,"r"); //Print the obtained content through the popen function if(NULL == fp) { printf("popen failed\n"); exit(-1); } //read //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); fread(msg.databuf,sizeof(msg.databuf),1,fp); pclose(fp); //Pass the obtained information through c_fd writeback client //ssize_t write(int fd, const void *buf, size_t count); write(fd,msg.databuf,sizeof(msg.databuf)); break; case CD: p = getDesDir(msg.cmd); chdir(p); //int chdir(const char *path); Path processing break; case GET: //get files file = getDesDir(msg.cmd); //Determine whether the file exists //int access(const char *pathname, int mode); if(access(file,F_OK) == -1) //non-existent { //Write error message strcpy(msg.databuf,"this file not exit"); //Return information to the client write(fd,msg.databuf,sizeof(msg.databuf)); } //The file does not exist //Open the file, copy the contents of the file to buf, and assign it to MSG Send data to client ffile = open(file,O_RDWR); //Open in a readable and writable manner len = lseek(ffile,0,SEEK_END); //Calculate the total length of the file lseek(ffile,0,SEEK_SET); //Move it to the beginning again, otherwise the data cannot be read read(ffile,buf,len); //Read content close(ffile); msg.type = DOFILE; //sign strcpy(msg.databuf,buf); //Copy the read content to MSG data write(fd,&msg,sizeof(msg)); //Send to client printf("get success\n"); break; case QUIT: printf("Client quit\n"); exit(-1); break; case PUT: //First judge whether the file exists and write the content when it is opened ffile = open(getDesDir(msg.cmd),O_RDWR|O_CREAT,0666); write(ffile,msg.buf,strlen(msg.buf)); close(ffile); default: strcpy(buf,"cmd not exit"); write(fd,msg.databuf,sizeof(msg.databuf)); break; } }
2, Client client implementation
/*********************************FTP-Client************************************ *Realize message sending between client and server (server only accepts processing instructions) *Date:2022-2-25 *Author:Xiao Yin *Version:1.0 *******************************************************************************/ #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <errno.h> #include <sys/stat.h> #include <fcntl.h> //Command macro definition #define LS 1 #define CD 2 #define PWD 3 #define LCD 4 #define LLS 5 #define GET 6 #define PUT 7 #define QUIT 8 #define DOFILE 9 #define MAX_LISTEN 20 / / maximum number of simultaneous listening struct FTP { int type; //type char databuf[1024]; //data char buf[1024]; //data char cmd[24]; //command }; struct FTP msg; int Get_CMD(char *msg); //Get command int MSG_Write_Handler(struct FTP msg,int fd); void MSG_Read_Handler(struct FTP msg,int fd); int main(int argc,char *argv[]) { int c_fd = 0; int ret = 0,mark = 0; struct sockaddr_in c_addr; //1. Create socket //int socket(int domain, int type, int protocol); c_fd = socket(AF_INET,SOCK_STREAM,0); if(c_fd == 0) { printf("socket error\n"); exit(-1); } //empty //void *memset(void *s, int c, size_t n); memset(&c_addr,'0',sizeof(struct sockaddr_in)); c_addr.sin_family = AF_INET; //uint16_t htons(uint16_t hostshort); //int atoi(const char *nptr); c_addr.sin_port = htons(atoi(argv[2])); //Port number conversion //int inet_aton(const char *cp, struct in_addr *inp); inet_aton(argv[1],&c_addr.sin_addr); //IP address //2. connect //int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1) { printf("connect error\n"); exit(-1); } //Connect successfully and print relevant IP information printf("connect success ip:%s\n",inet_ntoa(c_addr.sin_addr)); while(1) { //Create a child process to write commands to the parent process to receive and display data if(fork() == 0) //Child process created successfully { while(1) { //Each time a command is entered, the previous one will be cleared memset(msg.cmd,'0',sizeof(msg.cmd)); printf(">>>"); fflush(stdout); //printf("input cmd:"); gets(msg.cmd); //Send the command to the server //write(c_fd,msg.cmd,sizeof(msg.cmd)); MSG_Write_Handler(msg,c_fd); printf("---------------------send cmd done----------------\n\n"); } } while(1) { MSG_Read_Handler(msg,c_fd); } } //6. Close close(c_fd); return 0; } /*---------------------------------------Related function--------------------------------*/ //Get command int get_cmd_type(char *cmd ) { if(!strcmp("ls",cmd)) return LS; if(!strcmp("quit",cmd)) return QUIT; if(!strcmp("pwd",cmd)) return PWD; if(!strcmp("lls",cmd)) return LLS; if(!strcmp("lcd",cmd)) return LCD; if(strstr(cmd,"cd") != NULL) return CD; if(strstr(cmd,"get") != NULL) return GET; if(strstr(cmd,"put") != NULL) return PUT; return 100; } char *getDesDir(char *str) { char *p; p = strtok(str," "); p = strtok(NULL," "); printf("p is <%s>\n",p); return p; } int MSG_Write_Handler(struct FTP msg,int fd) { int ret = 0; char *dir = NULL; int filefd = 0; ret = get_cmd_type(msg.cmd); switch(ret) { case LS: case PWD: case CD: write(fd,msg.cmd,sizeof(msg.cmd)); break; case GET: //msg.type = DOFILE; write(fd,msg.cmd,sizeof(msg.cmd)); break; case LLS: system("ls"); break; case QUIT: write(fd,msg.cmd,sizeof(msg.databuf)); exit(-1); break; case PUT: //First, judge whether the file exists dir = getDesDir(msg.cmd); if(access(dir,F_OK) == 0) { printf("file not exit\n"); fflush(stdout);; } //There is a file to read this content filefd = open(dir,O_RDWR); read(filefd,msg.buf,sizeof(msg.buf)); close(filefd); //write in write(fd,&msg,sizeof(msg)); break; } } void MSG_Read_Handler(struct FTP msg,int fd) { int n_read = 0; int newfilefd = 0; n_read = read(fd,&msg,sizeof(msg)); if(n_read == 0) { printf("Server Had Quit\n"); exit(0); } else if(msg.type == DOFILE) { printf("had read file1\n"); char *file = getDesDir(msg.cmd); //Get this file newfilefd = open(file,O_RDWR | O_CREAT,0666); //Open readable and writable, create if not present write(newfilefd,msg.databuf,strlen(msg.databuf));//Write content to file close(newfilefd); printf(">>>"); fflush(stdout); } else { printf("---------------------get data------------------\n"); printf("%s\n",msg.databuf); printf("------------------------------------------------\n\n"); printf(">>>"); fflush(stdout); } }
3, Implementation results
summary
The best way to test your own learning is to do a relatively comprehensive small project, check for omissions and make up for deficiencies, and review and consolidate in time. Refueling duck