基于Socket套接字的FTP服务简单实现

基于Socket套接字的FTP服务简单实现

文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,它工作在 OSI 模型的第七层, TCP 模型的第四层, 即应用层, 使用 TCP 传输而不是 UDP, 客户在和服务器建立连接前要经过一个“三次握手”的过程, 保证客户与服务器之间的连接是可靠的, 而且是面向连接, 为数据传输提供可靠保证。

一、项目简介

1、利用套接字实现客户端和服务端的连接;
2、服务端和客户端可以互传文件;
3、客户端和服务端信息交互实现类似Linux系统下vi的快捷指令操作。

二、项目具体实现功能

1、客户端本地功能(xx代表文件或者文件夹名称):

  • 客户端查看当前文件路径:lpwd
  • 查看客户端当前目录下所有本地文件:lls
  • 客户端进入本地文件夹:lcd xx

2、客户端和服务端远程功能:

  • 客户端查看服务端的当前文件路径:pwd
  • 客户端查看服务端当前路径下所有文件:ls
  • 客户端进入服务端文件夹:cd xx
  • 客户端上传文件至服务端:upload xx
  • 客户端下载服务端文件到本地:download xx

三、代码实现

1、服务端代码实现:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>

//宏定义相关端指令
#define QUIT      0
#define LS        1
#define PWD       2
#define LLS       3
#define LPWD      4
#define LCD       5
#define CD        6
#define UPLOAD    7
#define DOWNLOAD  8     

struct Msg{
        int type;
        char cmd[128];
        char filename[128];
        char data[1024];
}msg;


char *getDir(char *cmd);//分割指令和文件,返回文件/文件夹名称
int analyse_Cmd(char *cmd);//分析指令
void getCmd(int c_fd,struct Msg msg);//根据指令做出响应

int main(int argc, char **argv)
{
	int s_fd;
	int c_fd;
	
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	int s_len = sizeof(struct sockaddr_in);
	int c_len = sizeof(struct sockaddr_in);
	
	memset(&s_addr,'\0',s_len);
	memset(&c_addr,'\0',c_len);
	
	//1.socket
	if((s_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){
	        printf("creat socket failed\n");
	        exit(-1);
	}
	//2.bind
	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&s_addr.sin_addr);
	
	if(bind(s_fd,(struct sockaddr *)&s_addr,s_len) != 0){
	        perror("bind");
	        exit(-1);
	}
	//3.listen
	if(listen(s_fd,10) != 0){
	        perror("listen");
	        exit(-1);
	}
	while(1){
		printf("wait connect -----\n");
		//4.accept
		if((c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&c_len)) == -1){
			perror("accept");
			exit(-1);
	    }else{
	        printf("get connect %s\n",inet_ntoa(c_addr.sin_addr));
	    }
	
	//创建子进程专门处理指令
	if(fork() == 0){
		 while(1){
			memset(&msg,'\0',sizeof(struct Msg));
			read(c_fd,&msg,sizeof(struct Msg));
			printf("cmd:%s\n",msg.cmd);
			getCmd(c_fd,msg);
		}
	}
	close(s_fd);
	close(c_fd);
	return 0;
}

//将指令和文件名称分割,得到文件/文件夹名称
char *getDir(char *cmd)
{
	char *p;
	p = strtok(cmd," ");
	p = strtok(NULL," ");
	return p;
}

//分析指令
int analyse_Cmd(char *cmd)
{
	if(!strcmp(cmd,"quit"))         return QUIT;
	if(!strcmp(cmd,"ls"))           return LS;
	if(!strcmp(cmd,"pwd"))          return PWD;
	
	if(strstr(cmd,"cd"))            return CD;
	if(strstr(cmd,"upload"))        return UPLOAD;
	if(strstr(cmd,"download"))      return DOWNLOAD;
	return -1;
}

//根据指令实现相应功能
void getCmd(int c_fd, struct Msg msg)
{
	int fd;
	FILE *fp;
	char *pret;
	char readBuf[1024] = {0};
	int ret = analyse_Cmd(msg.cmd);
	switch(ret)
	{
		case LS:
		case PWD:
			fp = popen(msg.cmd,"r");
			fread(msg.data,1,sizeof(msg.data),fp);
			write(c_fd,&msg,sizeof(struct Msg));
			pclose(fp);
			printf("msg.data \n %s\n",msg.data);
			break;
		
		case CD:
			pret = getDir(msg.cmd);
			if(chdir(pret) == -1){
			        perror("chdir");
			}
			getcwd(msg.data,sizeof(msg.data));
			write(c_fd,&msg,sizeof(struct Msg));
		break;
		
		case UPLOAD:
			pret = getDir(msg.filename);
			fd = open(pret,O_RDWR|O_CREAT,0600);
			write(fd,msg.data,strlen(msg.data)+8);
			close(fd);
			printf("upload success\n");
		break;
		
		case DOWNLOAD:
			msg.type = DOWNLOAD;
			strcpy(msg.filename,msg.cmd);
			pret = getDir(msg.cmd);
			if(open(pret,O_RDWR) < 0 ){
			        write(c_fd,"Fiel not found",20);
			        exit(-1);
			}else{
			        fd = open(pret,O_RDWR);
			        read(fd,readBuf,sizeof(readBuf));
			        strcpy(msg.data,readBuf);
			        write(c_fd,&msg,sizeof(struct Msg));
			        close(fd);
			}
			break;
		
		case QUIT:
			printf("client quit!\n");
			exit(1);
			break;
	}
}                                                                       

2、客户端代码实现:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

//宏定义相关指令
#define QUIT      0
#define LS        1
#define PWD       2
#define LLS       3
#define LPWD      4
#define LCD       5
#define CD        6
#define UPLOAD    7
#define DOWNLOAD  8     


struct Msg{
	int  type;
	char cmd[128];
	char filename[128];
	char data[1024];
}msg;

char *getDir(char *cmd);//分割指令和文件夹名称,返回文件/文件夹名称
int analyse_Cmd(char *cmd);//分析客户端发出的指令
void cmd_Handler(int c_fd, struct Msg msg);//处理客户端的指令
void getData(int c_fd, struct Msg msg);//得到服务端返回的数据

int main(int argc, char **argv)
{
	int c_fd;
	int mark = 0;
	struct sockaddr_in c_addr;
	int c_len = sizeof(struct sockaddr_in);
	memset(&c_addr,'\0',c_len);

	//1.socket
	if((c_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){
		printf("creat socket failed\n");
		exit(-1);
	}
	//2.connect
	c_addr.sin_family = AF_INET;
	c_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);

	if(connect(c_fd,(struct sockaddr *)&c_addr,c_len) != 0){
	 perror("connect");
	 exit(-1);
	}
	printf("connect success\n");
	
	while(1){
		memset(&msg,'\0',sizeof(struct Msg));
		if(mark == 0){
			printf(">");
		}
		gets(msg.cmd);
		if(strlen(msg.cmd) == 0){
	        if(mark == 1){
            	printf(">");
	        }
	        continue;
		}
		mark = 1;
		cmd_Handler(c_fd,msg);
		
		if(fork() == 0){
			getData(c_fd,msg);
		}
	}
	close(c_fd);
	return 0;
}

//返回文件/文件夹名称
char *getDir(char *cmd)
{
	char *p;
	p = strtok(cmd," ");
	p = strtok(NULL," ");
	return p;
}

//分析指令
int analyse_Cmd(char *cmd)
{
	if(!strcmp(cmd,"quit"))         return QUIT;
	if(!strcmp(cmd,"ls"))           return LS;
	if(!strcmp(cmd,"pwd"))          return PWD;
	if(!strcmp(cmd,"lls"))          return LLS;
	if(!strcmp(cmd,"lpwd"))         return LPWD;
	
	if(strstr(cmd,"lcd"))           return LCD;
	if(strstr(cmd,"cd"))            return CD;
	if(strstr(cmd,"upload"))        return UPLOAD;
	if(strstr(cmd,"download"))      return DOWNLOAD;
	return -1;
}

//处理指令内容
void cmd_Handler(int c_fd,struct Msg msg)
{
	int fd;
	int ret;
	char *pret;
	char readBuf[1024] = {0};
	ret = analyse_Cmd(msg.cmd);
switch(ret)
{
	case LS:
	case PWD:
	case CD:
	case DOWNLOAD:
	    write(c_fd,&msg,sizeof(struct Msg));
	    break;
	case LLS:
	    system("ls");
	    break;
	case LPWD:
	    system("pwd");
	    break;

	case LCD:
		pret = getDir(msg.cmd);
		if(chdir(pret) == -1){
			perror("chdir");
		}
		fd = chdir(pret);
		printf("dir: %s\n",pret);
		getcwd(msg.data,sizeof(msg.data));
		printf("change client dir:%s\n",msg.data);
		break;
	case UPLOAD:
		strcpy(msg.filename,msg.cmd);
		pret = getDir(msg.cmd);
		if(open(pret,O_RDWR) < 0){
			printf("no file\n");
		}else{
			fd = open(pret,O_RDWR);
			 read(fd,msg.data,sizeof(msg.data));
			 close(fd);
			 write(c_fd,&msg,sizeof(struct Msg));
			 printf("upload success\n");
		}
		break;
	
	case QUIT:
		write(c_fd,&msg,sizeof(struct Msg));
		exit(1);
		default:
		write(c_fd,&msg,sizeof(struct Msg));
	break;
	}
}

//
void getData(int c_fd,struct Msg msg)
{
	int fd;
	char *pret;
	
	memset(msg.data,'\0',sizeof(msg.data));
	read(c_fd,&msg,sizeof(struct Msg));
	if(msg.data == NULL){
		printf("no msg\n");
	}
	else if(msg.type == DOWNLOAD){
		pret = getDir(msg.filename);
		fd = open(pret,O_RDWR|O_CREAT,0600);
		write(fd,msg.data,strlen(msg.data)+8);
		printf("download success\n");
		close(fd);
	}
	else{
		printf("<---------------------->\n");
		printf("\n%s\n",msg.data);
		printf("<---------------------->\n");
	}
}


3、代码实现效果

第一步:客户端和服务端建立连接
在这里插入图片描述
第二步:客户端发送lls指令查看当前路径下所有本地文件,发送ls指令查看服务端当前路径下的文件
在这里插入图片描述
第三步:客户端发送uoload aa.txt上传本地文件aa.txt至服务端,发送download config.txt下载服务端config.txt文件到客户端
在这里插入图片描述
第四步:查看上传和下载的文件
在这里插入图片描述
第五步:客户端发送pwd指令查看服务端文件当前所在路径,然后cd …进入上层文件夹,然后cd xx回到当前文件夹
在这里插入图片描述
第六步:客户端发送指令查看本地文件夹所在目录,然后cd FTP进入FTP文件夹,cd …回到当前文件夹
在这里插入图片描述
第七步:客户端发送quit指令退出连接
在这里插入图片描述

4、总结:

在数据交互之前,要记得使用memset清空上一次客户端和服务端数据交换的内容。另外,除了自己写的简单指令外,还可以使用Linux自带的指令功能:输入ftp 127.0.0.1之后在输入乌班图的账号密码,用ftp+指令(如ftp ls)就可以使用相关指令了。
至此,基于Socket套接字实现简单FTP功能项目基本完成,如遇不足,烦请交流指正。

  • 17
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 基于GUI的FTP客户端的实现可以使用Java语言来编写。首先,需要使用Java的Swing或JavaFX库来创建用户界面。然后,需要使用Java的网络编程功能来实现FTP协议的功能。 在用户界面部分,可以使用Swing或JavaFX创建一个窗口,包含文件列表、上传按钮、下载按钮和连接按钮等组件。文件列表可以使用JTable或ListView来展示远程服务器上的文件列表。 连接按钮的点击事件可以触发一个方法,该方法通过使用Java的Socket类来建立与FTP服务器的连接。连接成功后,可以使用Socket发送FTP命令和接收服务器的响应。 上传按钮的点击事件可以触发一个方法,该方法通过Socket发送STOR命令来将本地文件上传到服务器。可以通过文件选择对话框来选择要上传的文件。上传过程中可以显示上传的进度条和状态信息。 下载按钮的点击事件可以触发一个方法,该方法通过Socket发送RETR命令来从服务器下载文件到本地。可以通过选择需要下载的文件,然后选择本地存储路径。下载过程中也可以显示下载的进度条和状态信息。 另外,还可以添加其他功能,如创建目录、删除文件等。这些功能可以通过发送不同的FTP命令来实现。 需要注意的是,FTP协议的实现可能涉及一些网络编程的知识,如处理socket连接、解析FTP响应等。同时,要保证在进行网络操作时要在子线程中执行,避免阻塞界面的用户交互。 总之,基于GUI的FTP客户端的实现需要结合Java的网络编程和Swing或JavaFX的界面设计来完成。这样用户就可以通过直观友好的界面来方便地上传下载文件和管理FTP服务器。 ### 回答2: 基于GUI的FTP客户端的实现可以使用Java编程语言来实现。下面是一个简单的300字的回答: 基于GUI的FTP客户端的实现需要使用Java的网络编程API,比如使用Java的Socket类来建立和FTP服务器的连接。可以使用Swing框架来创建用户界面,通过用户界面可以输入FTP服务器的地址、用户名和密码等信息,然后通过点击按钮来执行相应的FTP操作。 首先,我们需要创建一个主窗口,用户可以在该窗口中输入FTP服务器的地址、用户名和密码。然后,我们可以使用Java的Socket类来与FTP服务器建立连接,并通过FTP协议发送命令进行文件传输。 在界面中,我们可以使用一些按钮来执行不同的FTP操作,比如上传文件、下载文件、删除文件等。对于上传和下载操作,我们需要选择本地文件和服务器文件的路径,并通过Socket类来发送和接收文件数据。 另外,我们可以使用Swing的JList组件来显示FTP服务器中的文件列表,并通过选择文件来执行相应的操作。通过监听器来响应用户的操作,并使用Socket类来发送FTP命令。 为了提高用户体验,我们可以使用多线程来执行FTP传输操作,这样可以使得界面在文件传输过程中仍然响应用户的操作。 总之,基于GUI的FTP客户端的实现可以结合Java的网络编程API和Swing框架,通过用户界面和FTP协议实现用户与FTP服务器的交互,实现文件的上传、下载和删除等操作。 ### 回答3: 基于GUI的FTP客户端的实现需要使用Java编程语言。首先需要导入Java中的相关网络编程库,如java.net和java.io,以实现服务器的通信和文件传输。其次,需要使用Java的图形用户界面库,如Swing或JavaFX来构建用户界面。 在开始编写代码前,需要先准备好一个GUI界面,其中包括连接服务器的IP地址和端口号的输入框、登录用户名和密码的输入框、显示文件列表的区域、上传和下载文件的按钮等。 在代码中,首先需要创建一个FTP客户端对象,其中包含连接服务器、登录、上传、下载等各种操作的方法。在连接服务器时,需要获取用户输入的IP地址和端口号,并使用Java的Socket类进行连接。登录时,需要获取用户输入的用户名和密码,并使用FTP协议的USER和PASS命令进行验证。 在获取文件列表时,可以使用FTP协议的LIST命令获取服务器上的文件列表,并将其显示在GUI界面上。在上传和下载文件时,可以使用FTP协议的STOR和RETR命令进行文件传输。 通过在GUI界面上添加事件监听器,可以实现用户在点击按钮时触发相应的操作。例如,在点击上传按钮时,调用FTP客户端对象的上传方法,将用户选择的文件上传到服务器。 最后,需要注意处理异常情况,如无法连接服务器、登录失败、文件传输中断等。可以在代码中使用异常处理机制来捕获并处理这些异常,例如在连接服务器时捕获SocketException,登录时捕获FTPException等。在出现异常时,可以在GUI界面上显示相应的提示信息,以提醒用户出现了错误。 综上所述,基于GUI的FTP客户端的实现可以通过使用Java的网络编程和图形用户界面库来实现。通过创建FTP客户端对象并在GUI界面上添加按钮等控件,可以实现FTP服务器的连接、登录、文件上传和下载等操作。同时,也需要适当处理异常情况,以提高程序的稳定性和用户体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值