⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpcmd.c

📁 模拟linux平台下边的vsFtp服务器可以实现文件的断点续传和下载
💻 C
📖 第 1 页 / 共 3 页
字号:
		close(pasv_listen_socket);
		close(pasv_datatrans_socket);
	}
	
	Respond(226,"Directory send OK.");
	return 1;
}

int do_nlst(char *param)  //短列表
{
	int pips[2];
	//pid_t pid;
	if(pipe(pips)==0)
	{
		switch(fork())
		{
		case 0:
			 {
				close(1);//关掉标准输出
				//close(pips[0])  //pipe[0]代表读端
				if(dup(pips[1])==-1) //pips[1]代表写端,这里复制就是把标准输出重定向到管道的写端
				{
					perror("dup");
				}
				execlp("ls","ls",0);
				exit(1);
			 }
		case -1:
			{
				exit(-1);
			}

		default:
			{
				close(pips[1]);//主进程中关掉读端
				char buffer[1024] = {0};
				int size=0;
				while((size = read(pips[0], buffer, sizeof(buffer))) > 0)
				{
//					printf("%s",buffer);
					Respond(150,"Here comes the directory listing.");
					
					if(IsPASV==0)//IsPASV==0代表是主动模式
					{
//						printf("datatrans_socket=%d\n",datatrans_socket);
						write(datatrans_socket,buffer,strlen(buffer));
						close(datatrans_socket);					
					}
					else 
					{
						//printf("被动打印 短列表,被动监听套接字%d\n",pasv_listen_socket);
						
						//下边做被动模式
						struct sockaddr_in cliaddr;
						//int socket;//这个套接字是用来在被动模式下进行数据传送用的
						pasv_datatrans_socket=accept_socket(pasv_listen_socket,&cliaddr); //在被动模式下 datatrans_socket套接字是监听套接字
//						printf("短列表数据传输套接字.....%d\n",pasv_datatrans_socket);
						write(pasv_datatrans_socket,buffer,strlen(buffer));
						close(pasv_listen_socket);
						close(pasv_datatrans_socket);
					}
					
					Respond(226,"Directory send OK.");

					memset(buffer,0, sizeof(buffer));
				}
				close(pips[0]);
				return 1;
			}
		}
	}
		
	return 1;
}
int do_rmd(char *param)
{
	char buf[512]={0};
	int stat;
	if (IsAnonymous==1)
	{
		Respond(550,"Permission denied.");
		return 1;
	}
	Intercept_Parameter(buf,param);

	stat=rmdir(buf);
	if(stat<0)
	{
		Respond(550,"Remove directory operation failed.");
	}
	else
	{
		Respond(250,"Remove directory operation successful.");
	}
	return 1;
}
int do_mkd(char *param)
{
	char buf[512];
	int stat;
	if (IsAnonymous==1)
	{
		Respond(550,"Permission denied.");
		return 1;
	}
	Intercept_Parameter(buf,param);
	stat=mkdir(buf,0777);
	if(stat)
	{
		Respond(550,"Permission denied.");
	}
	if(buf[0]=='/')
	{
		Respond(257,"%s created",buf);
	}
	else
	{
		Respond(257,"%s/%s created",path,buf);
	}

	return 1;
}

int do_dele(char *param)
{
	int state=0;
	char buff[1024]={0};
	Intercept_Parameter(buff,param);
	state=unlink(buff);//删除文件,除了用unlink函数还可以用remove函数
	if(state==0)
	{
		Respond(250,"Delete operation successful.");
	}
	else
	{
		Respond(550,"Delete operation failed.");
	}
	return 1;
}
int do_help(char *param)//打印实现的命令
{
	char buf[] ="    USER    PASS    SYST    PWD    XPWD    TYPE    PORT    LIST    CWD    XCWD    CDUP    REIN    QUIT\n    PASV    MODE    RETR    STOR    APPE    REST    RNFR    RNTO    ABOR    DELE    RMD    XRMD    MKD\n    XMKD    NLST    SITE    SIZE    STAT    HELP    NOOP\n";
	//reply(214,"The following commands are recognized(*=>unimplemented).");
	char tmp[1024] = {0};
	sprintf(tmp,"214-The following commands are recognized(*=>unimplemented).\n");
	write(connected_socket,tmp,strlen(tmp));
	write(connected_socket,buf,strlen(buf));
	Respond(214,"Direct comments or bugs to bugs@bugs.com.");
	return 1;
}
int do_rein(char *param)
{
	//把全局变量设成初始值
	IsPASV=0;//用来标识被动模式
	IsAnonymous=0;//标记当前登入用户是否是匿名用户
	memset(userName,0,sizeof(userName) );//全局变量userName用来保存用户名
	memset(path,0,sizeof(path));
	userlogined=0;//用来标识是否有用户登入 0代表没有用户登入
	offset=0;//在断点续传中SERT指令要用的
	transfers_mode=0;//定义传输模式 0为普通模式,即没有采用断点续传模式 1为 APPE断点续传模式 2为REST断点续传模式
	//将当前进程的有效用户权限跟组用户权限设成root用户的 root用户的权限值为0
	setegid(0);
	seteuid(0);
	Respond(220,"Please specify the User.");
	return 1;
}
int do_quit(char *param)
{
	Respond(221,"Goodbye.");
	close(connected_socket);
	
	exit(1);
	return 1;
}


int do_rest(char *param) 
{
	char temp[512]={0};
	Intercept_Parameter(temp,param);
	Respond(350,"Restart position accepted (%s).",temp);
	offset=atoi(temp);//将断点续传的偏移量保存起来
	transfers_mode=2;//采用REST断点续传模式
	return 1;
}
int do_pasv(char *param)
{
	char ip[16]={0};
	int hight_byte;
	int low_byte;
	int stat;
	int port;
	struct sockaddr_in servaddr;
	int addr_len=sizeof(servaddr);
	pasv_listen_socket=CreateSocket();
	net_get_local_ip(ip);//将取得的IP地址放入ip中去
	init_socket_addr(&servaddr,ip,0);//初始化套接字地址 端口号为0代表,系统随机绑定一个端口
	
	memset(&servaddr,0,sizeof(servaddr));//清空套接字地址

	//只有root用户才可以对端口号低于1024的端口进行绑定所以在绑定端口前要更改当前进程r 有效用户ID跟有效用户组ID
	//获得当前的有效用户ID和有效用户组ID,以便 于在绑定后,进行还原
	//gid_t egid = getegid();//有效用户组ID
	//uid_t euid = geteuid();//有效用户ID
	//切换为root用户的权限
	//setegid(0);
	//seteuid(0);

	stat=bind_socket(pasv_listen_socket,&servaddr);//将套接字跟端口进行绑定

	if(stat<0)
	{
		printf("绑定套接字地址错误\n");
	}
	//切换回原来用户的权限
	//setegid(egid);
	//seteuid(euid);

	if(listen_socket(pasv_listen_socket,10)==0)
	{
//		printf("listen succ\n");
	}
	else
	{
		printf("listen failed\n");
	}//监听数据传输套接字
	//只有在绑定后才可以通过getsockname来获到

	getsockname(pasv_listen_socket,(struct sockaddr *)&servaddr,&addr_len);
	port=ntohs(servaddr.sin_port);//这里要将端口的网络字节序转换为本地字节序 重点

	low_byte=port&0xFF;//取出端口的低8位 十进制数
	hight_byte=port>>8;//取出端口的高8位 十进制数

//	printf("PASV IP:%s Port:%d\n",ip,port);

//	printf("发送信息是 Entering Passive Mode (%s,%d,%d)",ip,hight_byte,low_byte);
	//下边循环是将ip地址中的'.'转换成','
	int i=0;
	for(i=0;i<strlen(ip);i++)
	{
		if(ip[i]=='.')
		{
			ip[i]=',';
		}
	}
	//sleep(100);
	Respond(227,"Entering Passive Mode (%s,%d,%d)",ip,hight_byte,low_byte);
	return 1;
}
int do_rnfr(char *param)
{
	Intercept_Parameter(oldpath,param);
	Respond(350,"Ready for RNTO.");
	return 1;
}
int do_rnto(char *param)
{
	char newpath[PATH_MAX+1]={0};
	Intercept_Parameter(newpath,param);
	if(rename(oldpath,newpath)==0)
	{
		Respond(250,"Rename successful.");
	}
	else
	{
		Respond(500,"Rename error.");
	}

	return 1;
}	
int do_size(char *param)
{
	char file_name[512]={0};
	Intercept_Parameter(file_name,param);

	struct stat file_stat;
	
	if( S_ISDIR(stat(file_name,&file_stat)) )
	{
		Respond(550,"Could not get file size.");
	}
	else
	{
		Respond(213,"File \"%s\" size ( %d )",file_name,file_stat.st_size);
	}
	return 1;
}
int do_noop(char *param)
{
	Respond(200,"NOOP ok.");
	return 1;
}
int do_stor(char *param) //上传
{
	//被动模式 上传
	char file_name[512]={0};
	//int pid;

	Intercept_Parameter(file_name,param);

	stop_timeout(0);//设置超时
	g_isupload=1;
	if(IsPASV==1) 
	{
		//在被动模式下边要通过accept来接收客户端发送过来进行数据传输的的请求
		struct sockaddr_in cliaddr;
		//int socket;//这个套接字是用来在被动模式下进行数据传送用的
		pasv_datatrans_socket=accept_socket(pasv_listen_socket,&cliaddr); //在被动模式下 datatrans_socket套接字是监听套接字
		
		if(strcmp(file_name,"")!=0)
		{			

			if((child_pid=fork())==0)
			{
				int stat;
				//printf("子进程 connfd=%d\n",pasv_listen_socket);
				//printf("子进程 datatran_socket=%d\n",pasv_datatrans_socket);
				stat=Accept_Data(pasv_datatrans_socket,file_name);
				
				close(pasv_datatrans_socket);
				if(stat>0)
				{
					Respond(226,"File receive OK.");
				}
				close(pasv_listen_socket);
				To_Send_Signal_Start_Timeout();//开启超时
				exit(1);
			}
			else
			{
				//printf("父进程 connfd=%d\n",pasv_listen_socket);
				//printf("父进程 datatran_socket=%d\n",pasv_datatrans_socket);
				close(pasv_datatrans_socket);
				close(pasv_listen_socket);
			}
		}
	}
	else
	{
		//printf("主动模式下 上传数据");
		//以下是 主动传输模式下数据传输
		if(strcmp(file_name,"")!=0)
		{
			if((child_pid=fork())==0)
			{
				if(Accept_Data(datatrans_socket,file_name)>0) //当接收到客户端上传数据
				{	
					close(datatrans_socket);
					Respond(226,"File receive OK.");
				}
				else
				{
					close(datatrans_socket);
				}
				To_Send_Signal_Start_Timeout();//开启超时
				exit(1);
			}
			else
			{
				close(datatrans_socket);
			}
		}
	}
	offset=0;//当成功断点续传后要把偏移量置成0,以便后边继续上传
	return 1;
}
int do_retr(char *param) //断点 下载
{
	//被动模式 下载
	char file_name[512]={0};
	//int pid;

	Intercept_Parameter(file_name,param);

	stop_timeout(0);//关闭超时
	g_isdownload=1;
	if(IsPASV==1)
	{
		//在被动模式下边要通过accept来接收客户端发送过来进行数据传输的的请求
		struct sockaddr_in cliaddr;
		//int socket;//这个套接字是用来在被动模式下进行数据传送用的
		pasv_datatrans_socket=accept_socket(pasv_listen_socket,&cliaddr); //在被动模式下 datatrans_socket套接字是监听套接字

		if(strcmp(file_name,"")!=0)
		{
			if((child_pid=fork())==0)
			{
				int stat;
				//printf("子进程 connfd=%d\n",pasv_listen_socket);
				//printf("子进程 datatran_socket=%d\n",pasv_datatrans_socket);
				stat=Send_Data(pasv_datatrans_socket,file_name);
				
				close(pasv_datatrans_socket);
				if(stat>0)
				{

					Respond(226,"File send OK.");
				}
				close(pasv_listen_socket);

				To_Send_Signal_Start_Timeout();//开启超时

				exit(1);
			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -