[implementation of FTP cloud disk for linux small project]

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

Keywords: C Linux ftp

Added by prometheos on Sat, 26 Feb 2022 17:00:05 +0200