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

📄 ftppub.c

📁 模拟linux平台下边的vsFtp服务器可以实现文件的断点续传和下载
💻 C
字号:
#include <string.h>
#include <stdio.h>
#include <stdarg.h> //这个头文件是为va_start跟 va_end函数
#include <sys/param.h> //PATH_MAX声明的地方
#include <unistd.h> //write函数的头文件
#include <pwd.h> //struct passwd这个声明要用的
#include <sys/types.h>
#include <shadow.h>//getspnam()
#include <stdlib.h>//atoi()函数
#include <ctype.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/sem.h>
#include <signal.h>

#include <errno.h>


#include "ftppub.h"

#define SEND_BUFF 512
#define SEM_MAX 1

void Trim(char number1[])		//接受一个字符串,去除其前后空格
{
	int j,len;
	len=strlen(number1);
	for(j=0;j<len;j++)//去前面空格
	{
		if(number1[j]!=' ')
			break;
	}
	strcpy(number1,&number1[j]);
	
	for(j=strlen(number1);j>0;j--)//q去后面空格
	{
		if(number1[j-1]!=' ')
		{
			number1[j]='\0';
			
			break;
		}
	}
}

//服务端的响应函数
void Respond(int signal,char * message,...) //message
{
	va_list ap;
	char tmp[SEND_BUFF+1]={0};
	char respond_msg[SEND_BUFF+1]={0};
	va_start(ap,message);
	vsprintf(tmp,message,ap);
	va_end(ap);
	sprintf(respond_msg,"%d %s\r\n",signal,tmp);
//	printf("socket %d\n",connected_socket);
	write(connected_socket,respond_msg,strlen(respond_msg));
//	printf("发送响应内容          %s              \n",respond_msg);
}


int Intercept_Command(char *cmd,char * msg)
{
	char * p=0;
	if(msg==NULL)
	{
		return -1;
	}
	if(strcmp(msg,"")==0)//接收到空消息的时候
	{
		return -1;
	}
	p=strchr(msg,' ');//查找空格,有存在返回空格的指针
	if(p==NULL)
	{
		strcpy(cmd,msg);
		//cmd[strlen(cmd)-2]='\0';
	}
	else
	{
		strncpy(cmd,msg,p-msg);
	}
	int i=0;
	int len=strlen(cmd);
	for(;i<len;i++)
	{
		cmd[i]=toupper(cmd[i]);
	}
	return 1;
}

int Intercept_Parameter(char *par,char *msg)//截取命令的参数
{
	char * p=0;
	if(msg==NULL)
	{
		return -1;
	}
	p=strchr(msg,' ');//查找空格,有存在返回空格的指针
	if(p!=NULL)
	{
		strcpy(par,p+1);
	}
	else
	{
		memset(par,0,sizeof(*p));
	}
//	printf("参数的值是 %s\n",par);
	return 1;
}


int Login(char * username,char *input_pwd)//验证用户名跟密码,符合条件下更改用户目录 返回帐号密码类型1正确,2匿名,-1错误
{
	struct passwd *pw=NULL; // used for /etc/passwd 存放用户名,还有该 用户的路径
	struct spwd *spw=NULL; // used for /etc/shadow  存放用户名的密码
	char * real_passwd=NULL;
	char tmp[15]={0};	
	
	if ((pw = getpwnam(username)) == NULL)//判断用户名是否存在
	{
		printf("用户名不存在Login incorrect.\n");
		return -1;
		
	}
	//取得保存用户密码的结构体
	spw=getspnam(username);
	if (spw == NULL || (real_passwd = spw->sp_pwdp) == NULL) {
		printf("无密码Login incorrect.\n");
		return -1;
	}

	// 取得passwd的前12个字节作为种子
	strncpy(tmp, real_passwd, 12);
	// 判断输入的密码加密后是否与原密码相同
	if (strcmp(real_passwd, crypt(input_pwd, tmp)) != 0)
	{
			// 密码错误
			printf("密码错误Login incorrect.\n");
			return -1;
	}
	// 密码正确,改变程序有效权限(有效权限也可理解为临时权限),即设置当前进程只能以这个用户的权限进行访问,及这个用户所在组的权限进行访问

	setegid(pw->pw_gid);//要先改有效组然后再改有效用户
	seteuid(pw->pw_uid);

	if (pw->pw_dir) strncpy(path, pw->pw_dir,PATH_MAX);
	else strcpy(path, "/");
	chdir(path);


	return 1;
}


int Anonymous_Login(char * username,char *input_pwd)//验证用户名跟密码,符合条件下更改用户目录 返回帐号密码类型1正确,2匿名,-1错误
{
	struct passwd *pw=NULL; // used for /etc/passwd 存放用户名,还有该 用户的路径
	//struct spwd *spw=NULL; // used for /etc/shadow  存放用户名的密码
//	char * real_passwd=NULL;
//	char tmp[15]={0};	
	
	if ((pw = getpwnam(username)) == NULL)//判断用户名是否存在
	{
		printf("用户名不存在Login incorrect.\n");
		return -1;
		
	}

	//改变进程有效权限(有效权限也可理解为临时权限),即设置当前进程只能以这个用户的权限进行访问,及这个用户所在组的权限进行访问
	
	setegid(pw->pw_gid);//要先改有效组然后再改有效用户
	seteuid(pw->pw_uid);
	/*
	strncpy(path, pw->pw_dir,PATH_MAX);
	strcpy(anonymous_dir, "/");
	chdir(path);
	*/
	strncpy(anonymous_dir, pw->pw_dir,PATH_MAX);
	strcpy(path, "/");
	strcpy(cur_anonymous_dir,anonymous_dir);
	chdir(cur_anonymous_dir);
	return 1;
}


int separate_ip_port(char *parma,char *ip,int *port)//从字符串中分离出IP地址跟端口
{
	int strlength=strlen(parma);  //192,168,0,1,15,42
	
	int i=0;
	int count=0;//用来统计字符','的个数
	//将字符串的所有','字符都替换成'.'
	char hight_byte[4]={0};//存放端口的高字节
	char low_byte[4]={0};
	for(i=0;i<strlength;i++)
	{
		if(parma[i]==',')
		{
			parma[i]='.';
			count++;
		}
		if(count==4)
		{
			strncpy(ip,parma,i);
			strcpy(parma,parma+i+1);//把字符串后边的端口值移动到前边
			break;
		}
	}
	//取出端口值
	strlength=strlen(parma);
	for(i=0;i<strlength;i++)
	{
		if(parma[i]==',')
		{
			strncpy(hight_byte,parma,strlength-i-1);
			strcpy(low_byte,parma+i+1);
			break;
		}
	}
	*port=atoi(hight_byte)*256+atoi(low_byte);
	return 1;
}



//////////////////////////////////////////////////////////////////////////
//共享内存函数
int CreateShm()//创建一个共享内存
{
	
	key_t key;
	key = ftok(".", 'M');
	if((g_shmid = shmget(key, sizeof(FLUXCTRL), IPC_CREAT|IPC_EXCL|0666)) == -1) //IPC_EXCL作用就是确保在共享内存存在时再去创建就失败了
	{
//		printf("Shared memory segment exists - opening as client\n");
		if((g_shmid = shmget(key, sizeof(FLUXCTRL), 0)) == -1)
		{
			perror("shmget");
			exit(1);
		}
	}
	if((int)(g_segptr = (FLUXCTRL*)shmat(g_shmid,0,0)) == -1)//shmat第二个参数为NULL(即0)作用是让系统选择一个未使用的地址位置去附上共享内存段
	{
		perror("shmat");
		exit(1);
	}
	memset(g_segptr,0,sizeof(*g_segptr));
	return 1;
}
int Attach_Shm(int shmid)//将共享内存段附加到当前进程未使用的地址上去shared memory segment
{	

	if((int)(g_segptr = (FLUXCTRL*)shmat(shmid,0,0)) == -1)//shmat第二个参数为NULL(即0)作用是让系统选择一个未使用的地址位置去附上共享内存段
	{
		perror("shmat");
		exit(1);
	}
	

	return 1;
}

int Removeshm(int shmid)
{
	shmctl(shmid, IPC_RMID, 0);
//	printf("Shared memory segment marked for deletion\n");
	return 1;
}

int ChangeMode(int shmid, char *mode)
{
	struct shmid_ds myshmds;
	shmctl(shmid, IPC_STAT, &myshmds);
//	printf("Old permissions were: %o\n", myshmds.shm_perm.mode);
	//sscanf(mode, "%o", &myshmds.shm_perm.mode);
	shmctl(shmid, IPC_SET, &myshmds);
//	printf("New permissions are : %o\n", myshmds.shm_perm.mode);
	return 1;
}


void Create_Sem(int members)		//创建信号量
{
	key_t key = 1234;
	int i;
	union semun sem_opts;
//	printf("To create new sem with %d members!\n",members);
	fflush(stdout);
	if ((sem_id = semget(key,members,IPC_CREAT | IPC_EXCL | 0666)) == -1)
	{
		fprintf(stderr,"The semaphore is exist!\n");
		if((sem_id=semget(key,members,0))==-1)
		{
			perror("create sem error");
			exit(1);
		}
		//exit(0);
		
	}
	sem_opts.val = SEM_MAX;
	for (i = 0;i < members;i++)
	{
		if (semctl(sem_id,i,SETVAL,sem_opts) == -1)
		{
			fprintf(stderr,"set val error!\n");
			exit(0);
		}
		
	}
	
	
}

int P_Sem(int sem_id,int sem_num)		//P操作
{
	
	struct sembuf sem_b;
	sem_b.sem_num = sem_num;
	sem_b.sem_op = -1;
	sem_b.sem_flg = SEM_UNDO;
	if (semop(sem_id,&sem_b,1) == -1)
	{
		return 0;
	}
	return 1;
}
int V_Sem(int sem_id,int sem_num)		//V操作
{
	
	struct sembuf sem_b;
	sem_b.sem_num = sem_num;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;
	if (semop(sem_id,&sem_b,1) == -1)
	{
		return 0;
	}
	return 1;
}
int del_semvalue(int sem_id)		//删除信号量
{
	union semun sem_union;
	if(semctl(sem_id,0,IPC_RMID,sem_union) == -1)
	{
		printf("\nsem delete fail!\n");
		return 0;
	}
//	printf("\nsem delete!");
	fflush(stdout);
	return 1;
}







void Up_Total(int num)//服务器上传文件总数
{
	P_Sem(sem_id,0);
	g_segptr->uptotal+=num;
	V_Sem(sem_id,0);
}
void Down_Total(int num)//服务器下载文件总数
{
	P_Sem(sem_id,1);
	g_segptr->downtotal+=num;
	V_Sem(sem_id,1);
}
void Up_Size(int size)//服务器上传文件大小
{
	P_Sem(sem_id,2);
	g_segptr->upsize += size;
	V_Sem(sem_id,2);
}
void Down_Size(int size)//服务器下载文件大小
{
	P_Sem(sem_id,3);
	g_segptr->downsize += size;
	V_Sem(sem_id,3);
}

int Get_Up_Total()//服务器上传文件总数
{
	int temp;
	P_Sem(sem_id,0);
	temp = g_segptr->uptotal;
	V_Sem(sem_id,0);
	return temp;
}
int Get_Down_Total()//服务器下载文件总数
{
	int temp;
	P_Sem(sem_id,1);
	temp = g_segptr->downtotal;
	V_Sem(sem_id,1);
	return temp;
}
long Get_Up_Size()//服务器上传文件大小
{
	long temp;
	P_Sem(sem_id,2);
	temp = g_segptr->upsize;
	V_Sem(sem_id,2);
	return temp;
}
long Get_Down_Size()//服务器下载文件大小
{
	long temp;
	P_Sem(sem_id,3);
	temp = g_segptr->downsize;
	V_Sem(sem_id,3);
	return temp;
}


void start_timeout(int signal)
{
	//printf("子进程发送信号过来\n");
	is_have_timeout=1;
}

void stop_timeout(int signal)
{
	is_have_timeout=0;
}


void To_Send_Signal_Start_Timeout()
{
	pid_t ppid;
	ppid=getppid();//取得父进程ID
	kill(ppid,SIGUSR1);//发送SIGUSR1信号
}



//读取配制文件  返回0就是读取失败 1就是成功 第一个参数是数据要存的指针,第二个是最多读取信息数 第三个指向是用来返回最终读取了多少条信息
int ReadConfigInfo(struct configInfo * config,int maxReadCount,int *alreadyReadCount)
{
    FILE * file=fopen("miniftp.conf","r");
    if(file==NULL)
    {
        printf("File Open Error");
        return 0;
    }
    
    //struct configInfo config[10];
    char buffer[128]={0};
   	int buffer_size=128;
    int read_count=0;
    while(fgets(buffer,buffer_size,file)!=NULL)
    {
        if(buffer[0]!=35 && buffer[0]!='\n')  //#的ascii码为35
        {
            int position=0; //字符保存的位置 
            char * pBuffer=buffer;
            //取出键名 
            while(!isspace(*pBuffer))
            {
                *(config[read_count].keyname+position)=*pBuffer;//将字符保存进结构体 
                position++;
                pBuffer++;
            }
            *(config[read_count].keyname+position)='\0';
            //printf("%s\t",&(config[read_count].keyname));
            
            //从键名后查找非空字符的位置 
            while(isspace(*(++pBuffer)))
            {}
            position=0;
            
            //将非空字符保存起来,直到回车符为止 
            while(*pBuffer!='\n')
            {
                *(config[read_count].value+position)=*pBuffer;
                position++;
                pBuffer++;
            }
            *(config[read_count].value+position)='\0';
            //printf("%s\n",&(config[read_count].value));
            read_count++;
            if(read_count>=maxReadCount)
			{
				break;
			}
        }        
    }
	/*
    int size;
    for (size=0;size<read_count; size++)
	{
	printf("%s\t",config[size].keyname);
	printf("%s\n",config[size].value);
	}
	*/
	*alreadyReadCount=read_count;
    fclose(file);
    //getchar();
    return 1;
}











⌨️ 快捷键说明

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