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

📄 ftpd.c

📁 模拟linux平台下边的vsFtp服务器可以实现文件的断点续传和下载
💻 C
字号:
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "ftpdaemon.h"
#include "ftpnet.h"
#include "ftppub.h"
#include "ftpcmd.h"
#include <errno.h>

#define INFO_BUFF_SIZE   100

//程序中所有的全局变量都在这里被定义

int connected_socket;//connected_socket这个是已连接套接字,用来跟客户端进行命令传输
int datatrans_socket;//这个套接字用来跟客户端进行数据传输
int IsPASV=1;//用来标识被动模式
int IsAnonymous;//标记当前登入用户是否是匿名用户
char userName[512];//全局变量userName用来保存用户名
char path[PATH_MAX+1];
int userlogined=0;//标记用户以登入

int pasv_datatrans_socket;//用在被动模式下进行数据传输
int pasv_listen_socket;//用在被动模式下进行监听的套接字

int timeout=10;//这里定超时10秒后
int is_have_timeout=1;//用来标识现在是否有进行超时,默认情况下有进行超时,当值为1时有进行超时 值为0时不进行超时

int child_pid;//保存子进程ID
long offset=0;//在断点续传中SERT指令要用的
int transfers_mode=0;//定义传输模式 0为普通模式,即没有采用断点续传模式 1为 APPE断点续传模式 2为REST断点续传模式
char anonymous_dir[PATH_MAX+1]={0};//匿名用户的根目录
char cur_anonymous_dir[PATH_MAX+1]={0};//匿名用户的物理地址
char oldpath[PATH_MAX+1]={0};//这个字符数组用来在进行重命的时候用

int g_isupload=0;//是否在上传
int g_isdownload=0;//是否在下载

int downspeed;//限制下载速 度
int upspeed;//限制上传速 度

int g_shmid=0;//共享内存标识

int sem_id;//信号集标识

int port_no=21;//端口号



FLUXCTRL * g_segptr;//指向服务器共享信息结构体


int  ftp_server_start()
{

//读取出配制信息

	int size=5;
	int alreadyRead=0;//存放以读取配制信息的个数
	//测试接收配制文件
	struct configInfo * config=(struct configInfo *)malloc(sizeof(struct configInfo)*size);
	//取出配制信息
	if(ReadConfigInfo(config,size,&alreadyRead)==1)
	{
		
		int i=0;
		for(;i<alreadyRead;i++)
		{
//			printf("\n名称为:%s , 值为: %s\n",config[i].keyname,config[i].value);
			if(strcmp(config[i].keyname,"maxup")==0)
			{
				upspeed=atoi(config[i].value);
			//	printf("第%d个,上传最大......................[%d]\n",i,upspeed);
			}else if(strcmp(config[i].keyname,"maxdown")==0)
			{
				downspeed=atoi(config[i].value);
			//	printf("第%d个,下载最大......................[%d]\n",i,downspeed);
			}else if(strcmp(config[i].keyname,"timeout")==0)
			{
				timeout=atoi(config[i].value);
			//	printf("第%d个,超时..........................[%d]\n",i,timeout);
			}else if(strcmp(config[i].keyname,"port_no")==0)
			{
				port_no=atoi(config[i].value);
			//	printf("第%d个,端口号........................[%d]\n",i,port_no);
			}
		}
		
	}
	else
	{
		printf("读取配制文件出错\n");
		exit(1);
	}



	struct sockaddr_in socketaddr;
	int listen_sock;//监听套接字

	int childpid,state;
	//socklen_t len;//存放套接字地址长度

	memset(&socketaddr, 0, sizeof(socketaddr));//将套接字地址清零
	listen_sock=CreateSocket();//创建一个监听套接字
	
	if(listen_sock<0)
	{
		printf("创建套接字失败");
		exit(-1);
	}
//	printf("绑定端口号是...............[%d]\n",port_no);
	init_socket_addr(&socketaddr,0,port_no);

	state=bind_socket(listen_sock,&socketaddr);
	if(state<0)
	{
		printf("绑定出错");
		exit(-1);
	}
	state=listen_socket(listen_sock,10);//第二个参数10代表的是同一时刻最多连接10个用户
	
	if(state)
	{
		printf("监听出错");
		exit(-1);	
	}
	signal(SIGCHLD, SIG_IGN);//防止子进程结束后变成僵死进程,这里子进程结束后会产生SIGCHLD信号,当父进程接收到这个信号时忽略掉

	signal(SIGINT,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	//	signal(SIGTERM,SIG_IGN);
	signal(SIGPIPE,SIG_IGN);
	
	
	for (;;)
	{
		//pause();
//		printf("进入等待用户连接...\n");


		connected_socket=accept_socket(listen_sock,&socketaddr);


//		printf("有一用户连接连接进来...\n");
//		printf("connected_socket=%d",connected_socket);
		if(connected_socket<0)
		{
			//"接收用户请求时连接出错"
			continue;
		}
		else
		{
			if(0==(childpid=fork()))//当childpid的值==0的时候代表的是子进程
			{	

				signal(SIGUSR1,start_timeout);//SIGUSR1信号在这里的作用是由负责数据传输的进程向父进程发送,当父进程接收到信号后就开启超时
				
				//Attach_Shm(g_shmid);

				//在fork出来的子进程中accept_sock套接字跟父进程中的accept_sock同指向一个内核缓冲区
				//在子进程中不需要监听套接字所以关掉
				close(listen_sock);//关闭掉监听套接自

				char recv_info_buffer[INFO_BUFF_SIZE]={0};//存放客户端发送给服务端的消息 例客户端发送的信息为 abc\r\n 的字符串,这里的字符串不会以'\0'结尾
				char cmd_buf[CMD_BUFF_SIZE]={0};//命令缓冲区
				
				Respond(220,"welcome to login miniftpd 1.0");

				int i=0;
				int res;
				while(1)
				{
					//超时处理中, 由于在超时时
					if((res=Is_Time_Out(connected_socket, timeout))==0)//传入connected_socket,判断sec时间内是否超时,返回值大于0代表有多少个可读事件,超时返回0,错误返回-1
					{
						if(is_have_timeout==1)//代表现在有进行数据传送,传输命令不进行超时
						{
							exit(1);		
						}else
						{
							continue;		
						}
						
					}
					else if(res==1)
					{
						memset(recv_info_buffer,0,sizeof(recv_info_buffer));//这里一定要清缓冲区
						my_read(connected_socket,recv_info_buffer,INFO_BUFF_SIZE);		
					}
					else
					{
						//perror("DDDDDDDDDDDD");
						//printf("DDDDDDDDDD=%d\n",errno);
						//exit(1);
						continue;
					}
					

					i=0;

//					printf("接收的消息是: %s 结束\n",recv_info_buffer);
					memset(cmd_buf,0,sizeof(cmd_buf));
					Intercept_Command(cmd_buf,recv_info_buffer);

					
//					printf("命令: %s\n",cmd_buf);

					/*
					for(i=0;;i++)
					{
						if(strcmp(cmd_list[i].cmd,"") == 0)
						{
							Respond(500,"Unknown command.");
							break;
						}
						if(strcmp(cmd_list[i].cmd,cmd_buf)==0)
						{
							(cmd_list[i].cmd_handler)(recv_info_buffer);
							break;
						}

					}
*/

					while(strcmp(cmd_list[i].cmd,"")!=0)
					{
						if(strcmp(cmd_list[i].cmd,cmd_buf)==0)
						{
// 
// 							if(strcmp(cmd_list[i].cmd,"STAT")==0)
// 							{
// 								printf("开始执行......................%s  命令,其函数指针的值是 %d\n",cmd_buf,(int)(cmd_list[i].cmd_handler));
// 								//do_stat(recv_info_buffer);
// 							}
							if(cmd_list[i].cmd_handler==NULL)
							{
								Respond(500,"Unknown command.");
							}
							else
							{
								(cmd_list[i].cmd_handler)(recv_info_buffer);
							}
							break;
						}
						//printf("执行结构体数组中的第 %d 个命令\n",i);
						i++;
					}
					
					if(strcmp(cmd_list[i].cmd,"")==0)
					{
						if(cmd_buf[0]!=-1)
						{
//							printf("非法字符的内容为.............[ %s ]\n",cmd_buf);
//							printf("第一个非法字符%d,%d\n",cmd_buf[0],cmd_buf[1]);
							Respond(500,"Unknown command.");
						}
					}
				}

				close(connected_socket);
				exit(0);
			}
		}
		close(connected_socket);
	}
}

int main(int argc,char *argv[])
{
	//创建Ftp守护进程
	return daemon_ctrl(argc,argv,ftp_server_start);
}

⌨️ 快捷键说明

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