在linux内实现FTP传输

FTP项目实现过程

架构及功能

架构

分为用户端与客户端

功能

基础功能

1.显示服务端文件 -ls
2.下载服务端文件 -get
3.上传客户端文件 -put
4.切换服务端目录 -cd
5.退出 -quit

高级功能

1.用户密码验证
2.下载上传的文件通过md5验证
3.显示历史记录

架构实现

服务端

    s_fd=socket(AF_INET,SOCK_STREAM,0);//socket
	if(s_fd==-1)
	{
		logwrite("perror bind: %s",s_fd);
		exit(-1);
	}
	int on=1;
	if((setsockopt(s_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
	{
		perror("setsockopt failed");
		exit(EXIT_FAILURE);
	}
	//2.bind
	s_addr.sin_family=AF_INET;
	s_addr.sin_port=htons(8989);
	s_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	ret=bind(s_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in));
	if (ret==-1)
	{
		logwrite("perror bind: %s",ret);
		exit(-1);
	}
	//3.listen
	ret2=listen(s_fd,10);
	if (ret2==-1)
	{
		logwrite("perror listen: %s",ret2);
		exit(-1);
	}
	//4.accpet
	int len=sizeof(struct sockaddr);
	c_fd=accept(s_fd,(struct sockaddr*)&c_addr,&len);
		if (c_fd==-1)
		{
			logwrite("perror accpet: %s",c_fd);
			exit(-1);
		}
	

用户端

c_fd=socket(AF_INET,SOCK_STREAM,0);
	if (c_fd==-1)
	{
		logwrite("perror connect: %s",c_fd);
		exit(-1);
	}

	c_addr.sin_family=AF_INET;
	c_addr.sin_port=htons(8989);
	c_addr.sin_addr.s_addr=htonl(INADDR_ANY);



	con=connect(c_fd,(struct sockaddr*)&c_addr,sizeof(struct sockaddr));
	if (con==-1)
	{
		logwrite("perror connect: %d",con);
		exit(-1);
	}

功能实现

需要定义一个用来来回传输数据的结构体

enum FTP_CMD
{
	//ls 
	FTP_CMD_LS=0,
	//get 下载
	FTP_CMD_GET=1,
	//put 上传 
	FTP_CMD_PUT=2,
	//quit 断开连接
	FTP_CMD_QUIT=3,
	//cd 切换服务端目录
	FTP_CMD_CD=4,
	//登录错误
	FTP_CMD_ERROR=5,
	//显示历史记录
	FTP_CMD_HOST=6
};

struct Msg{
	//命令 
	enum  FTP_CMD cmd;
	//命令的参数 get test.c
	char atgs[32];
	//md5
	char md5[64];
	//文件数据长度
	int datalen;
	//test.c打的内容长度未知
	char data[5000];
};

因为是在linux下实现功能因此可以使用popen来令自己在用户端输入的ls命令被linux运行(host也差不多但是不是调用系统命令) ,因此需要将命令输入到 atgs内,而get、put、cd的命令需要将get、put、cd剔除后再放入atgs中,因此需要一个自定义函数来完成。

 fgets(buf,sizeof(buf),stdin);//输入命令
 cmd = get_cmd(buf,msg_send);//调用自定义的hget_cmd函数
int get_cmd(char *buf,struct Msg * remsg)
{
	FILE *f=NULL;
	int ret;
	long chang;
	if (memcmp(buf,"ls",2)==0)//识别ls命令
	{
	   	strcpy(remsg->atgs,buf);//将
	   	return 0;
	}
	else if (memcmp(buf,"get",3)==0)//识别get命令
	{
	   	remsg=lianjiemingling(buf,remsg);//剔除get
	   	return 1;
	}
	else if (memcmp(buf,"put",3)==0)//识别put命令
	{
		remsg=lianjiemingling(buf,remsg);剔除put
		get_md5(remsg->atgs,remsg->md5);//记录md5值
		logwrite("yuan md5:%s\n",remsg->md5);
		chang=get_length(remsg->atgs);//记录文件长度
		if (chang==-1||chang>sizeof(remsg->data))
		{
			logwrite("perror get_length:%ld",chang);
			return -1;
		}
		f=fopen(remsg->atgs,"r");//打开需要上传文件
		logwrite("perror get : %s\n",remsg->atgs);
		if (NULL!=f)
		{
			ret=fread(remsg->data,1,chang,f);//读取文件内容
			logwrite("perror get read: %s",remsg->data);
			remsg->datalen=ret;
			fclose(f);
		}
	   	return 2;
	}
	else if (memcmp(buf,"cd",2)==0)//识别cd命令
	{
		remsg=lianjiemingling(buf,remsg);剔除cd
	   	return 4;
	}
	else if (memcmp(buf,"quit",4)==0)//识别quit命令
	{
	   	return 3;
	}
	else if (memcmp(buf,"host",4)==0)//识别host命令
	{
		strcpy(remsg->atgs,buf);
		return 6;
	}
	else 
	{
	   	return 5;

	}	

    
}

struct Msg *lianjiemingling(char *buf,struct Msg *remsg)//将get、put、cd剔除后再放入atgs中
{
	
	char *get;
	get=strstr(buf," ");
	while(1)
	{
		if (NULL==get|| *get=='\0')
		{
			break;
		}
		get+=1;
		if ( *get!=' ')
		{
			break;
		}
	}
	strncpy(remsg->atgs,get,strlen(get)-1);	//去除\n
	return remsg;	
}

命令传输到服务端后,服务端需要识别命令并作出对应的操作

while(1)
	{	

		memset(msg_send,0,sizeof(struct Msg));
		memset(msg_recv,0,sizeof(struct Msg));
		ret=recv(c_fd,msg_recv,sizeof(struct Msg),0);//读取数据
		logwrite("perror recv: %d\n",ret);
		msg_send=chuli(msg_recv,msg_send);//识别命令

		ret=send(c_fd,msg_send,sizeof(struct Msg),0);//发送处理后的数据
		logwrite("perror send: %d\n",ret);
		if (msg_recv->cmd==FTP_CMD_QUIT)//如果接收到退出,就关闭服务端
		{
			printf("client quit\n");
			logwrite("client quit\n");
			break;
		}
	}
struct Msg * chuli(struct Msg * get_cmd,struct Msg *out_cmd) //处理命令
{
	FILE *f;
	int ret;
	long chang;
	out_cmd=get_cmd;
	static struct host *hostcmd;
	switch(out_cmd->cmd)
	{
	case FTP_CMD_LS://ls
		addcmd(&hostcmd,get_cmd->atgs);//记录ls命令至历史记录中
		f=popen(out_cmd->atgs,"r");
		if (NULL!=f)
		{
			fread(out_cmd->data,1,5000,f);//读取popen的数据至data中
			
		}
		break;
	case FTP_CMD_GET://get
		getaddcmd(&hostcmd,get_cmd->atgs);//记录get命令至历史记录中
		get_md5(out_cmd->atgs,out_cmd->md5);//记录md5值
		logwrite("yuan md5:%s\n",out_cmd->md5);
		chang=get_length(out_cmd->atgs);//记录文件长度
		if (chang==-1||chang>sizeof(out_cmd->data))
		{
			logwrite("perror get_length:%ld",chang);
			break;
		}
		printf("length:%ld\n", chang);
		f=fopen(out_cmd->atgs,"r");//打开需要下载文件
		logwrite("perror get : %s\n",out_cmd->atgs);
		if (NULL!=f)
		{
			ret=fread(out_cmd->data,1,chang,f);//读取文件内容
			logwrite("perror get read: %s",out_cmd->data);
			out_cmd->datalen=ret;
			fclose(f);
		}
		break;
	case FTP_CMD_PUT://put
		putaddcmd(&hostcmd,get_cmd->atgs);//记录put命令至历史记录中
		f=fopen(out_cmd->atgs,"w");//在服务端创建上传文件
		if(f!=NULL)
		{
			ret=fwrite(out_cmd->data,1,out_cmd->datalen,f);//写入文件内容

			fclose(f);
			get_md5(out_cmd->atgs,out_cmd->md5);//获取md5
			logwrite("xian md5:%s\n",out_cmd->md5);
			if (memcmp(out_cmd->md5,get_cmd->md5,32)!=0)//对比md5值若不一致,则删除文件并打印两个md5值
			{
				remove(out_cmd->atgs);
				logwrite("client md5:%s,server md5:%s");
			}
		}
		break;
	case FTP_CMD_QUIT:
		break;
	case FTP_CMD_CD://cd
		cdaddcmd(&hostcmd,get_cmd->atgs);//记录cd命令至历史记录中
		ret =chdir(get_cmd->atgs);//调用系统函数chdir切换目录
		if (ret==-1)
		{
			logwrite("perror cd %s",get_cmd->atgs);
		}
		break;
	case FTP_CMD_HOST://host
		addcmd(&hostcmd,get_cmd->atgs);//将历史记录调出
		gethost(hostcmd,out_cmd->data);	//放入data中
	default:
			break;		
	}
	return out_cmd;
}

服务端在完成操作后再将完成的数据发送回用户端,用户端根据指令再做操作

void chuli(struct Msg * get_cmd,struct Msg *out_cmd)//用户端操作
{
	FILE *fd=NULL;
	int ret;
	switch(get_cmd->cmd)
	{
	case FTP_CMD_LS:
		printf("%s\n", get_cmd->data);//打印目录
		break;
	case FTP_CMD_GET:	
		fd=fopen(get_cmd->atgs,"w");//创建下载的文件
		if(fd!=NULL)
		{
			ret=fwrite(get_cmd->data,1,get_cmd->datalen,fd)//写入数据

			fclose(fd);
			get_md5(out_cmd->atgs,out_cmd->md5);//获取md5值
			logwrite("xian md5:%s\n",out_cmd->md5);
			if (memcmp(out_cmd->md5,get_cmd->md5,32)!=0)//对比md5值若不一致,则删除文件并打印两个md5值
			{
				remove(out_cmd->atgs);
				logwrite("client md5:%s,server md5:%s");
			}
		
		}
		break;
	case FTP_CMD_PUT:
		break;
	case FTP_CMD_QUIT:
	case FTP_CMD_CD:
	case FTP_CMD_HOST:
		printf("%s\n", get_cmd->data);//打印历史记录
		break;
	default:
		break;
	}

}

这就是基本的实现步骤,另外历史记录是用链表做的还有几个函数如下(由于我是在用户端直接分割命令所以在记录时需要蒋继阁命令分开处理):

struct host//链表结构体
{
	char cmd[32];
	struct host *pnext;
};
void addcmd(struct host **head,char *buf)//记录ls命令
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	strcpy(nope->cmd,buf);
	nope->pnext=*head;
	*head=nope;
	
}
void putaddcmd(struct host **head,char *buf)记录put命令
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	char but[32]="put ";
	strcat(but,buf);
	strcat(but,"\n");
	strcpy(nope->cmd,but);
	nope->pnext=*head;
	*head=nope;
	
}
void getaddcmd(struct host **head,char *buf)记录get命令
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	char but[32]="get ";
	strcat(but,buf);
	strcat(but,"\n");
	strcpy(nope->cmd,but);
	nope->pnext=*head;
	*head=nope;
	
}
void cdaddcmd(struct host **head,char *buf)记录cd命令
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	char but[32]="cd ";
	strcat(but,buf);
	strcat(but,"\n");
	strcpy(nope->cmd,but);
	nope->pnext=*head;
	*head=nope;
}

void gethost(struct host *p,char *buf)//遍历链表将历史记录拷贝出来
{
	struct host* head=p;
	while(head!=NULL)
	{
		strcat(buf,head->cmd);
		head=head->pnext;
	}
}

用户密码验证怎需要在输入命令之前进行,在验证成功并且正确后才能进行下一步:

struct password//验证用的结构体
{
	enum  FTP_CMD cmd;

	char name[64];

	char pass[64];
};

	struct password dl;//用户端输入用户名和密码
	printf("name:");
	scanf("%s",dl.name);
	printf("pass:");
	scanf("%s",dl.pass);
	logwrite("nmae:%s  pass%s\n",dl.name,dl.pass);
	ret=send(c_fd,&dl,sizeof(struct password),0);
	logwrite("perror send: %d\n",ret);
	ret=recv(c_fd,&dl,sizeof(struct password),0);
	logwrite("perror recv: %d\n",ret);

	if (FTP_CMD_ERROR==dl.cmd)//错误就退出
	{
		printf("name or pass error\n");
		return -1;
	}

	struct  password dl;//客户端进行验证
	char name[64];
	char passw[64];
	ret=recv(c_fd,&dl,sizeof(struct password),0);
	logwrite("nmae:%s  pass%s\n",dl.name,dl.pass);
	FILE *fd=fopen("passw.txt","r");//打开用户名和密码放置的文件
	if (NULL!=fd)
	{
		fscanf(fd,"%s %s",name,passw);读取用户名和密码
		fclose(fd);
	}
	if (strcmp(name,dl.name)!=0||strcmp(passw,dl.pass)!=0)//验证
	{
		dl.cmd=FTP_CMD_ERROR;
	}
	ret=send(c_fd,&dl,sizeof(struct password),0);//错误就退出
	if (dl.cmd==FTP_CMD_ERROR)
	{
		return -1;
	}

另外还有一个记录日志log,用来在写代码时进行调试log的文件如下
log.c

#include 
#include  
#include 
#include 
FILE * flog;
void logcreate(char *format)
{
	flog=fopen(format,"a+");
}	
void logwrite(char *format, ...)
{
	va_list aptr;
	va_start(aptr,format);
	vfprintf(flog,format,aptr);
	va_end(aptr);
	fflush(flog);
}
void logout()
{
	fclose(flog);
	flog=NULL;
}

log.h

#ifndef _LOG_H
#define _LOG_H
void logcreate(char *format);

void logwrite(char *format, ...);

void logout();

#endif

其他几个文件如下:
server.c 服务端

#include 
#include  "log.h"
#include          
#include 
#include 
#include 
#include 
#include 
#include "msg.h"
#include "util.h"
#include "ftplink.h"

struct Msg * chuli(struct Msg * get_cmd,struct Msg *out_cmd)
{
	FILE *f;
	int ret;
	long chang;
	out_cmd=get_cmd;
	static struct host *hostcmd;
	switch(out_cmd->cmd)
	{
	case FTP_CMD_LS:
		addcmd(&hostcmd,get_cmd->atgs);
		f=popen(out_cmd->atgs,"r");
		if (NULL!=f)
		{
			fread(out_cmd->data,1,5000,f);
			
		}
		break;
	case FTP_CMD_GET:
		getaddcmd(&hostcmd,get_cmd->atgs);
		get_md5(out_cmd->atgs,out_cmd->md5);
		logwrite("yuan md5:%s\n",out_cmd->md5);
		chang=get_length(out_cmd->atgs);
		if (chang==-1||chang>sizeof(out_cmd->data))
		{
			logwrite("perror get_length:%ld",chang);
			break;
		}
		printf("length:%ld\n", chang);
		f=fopen(out_cmd->atgs,"r");
		logwrite("perror get : %s\n",out_cmd->atgs);
		if (NULL!=f)
		{
			ret=fread(out_cmd->data,1,chang,f);
			logwrite("perror get read: %s",out_cmd->data);
			out_cmd->datalen=ret;
			fclose(f);
		}
		break;
	case FTP_CMD_PUT:
		putaddcmd(&hostcmd,get_cmd->atgs);
		f=fopen(out_cmd->atgs,"w");
		if(f!=NULL)
		{
			ret=fwrite(out_cmd->data,1,out_cmd->datalen,f);

			fclose(f);
			get_md5(out_cmd->atgs,out_cmd->md5);
			logwrite("xian md5:%s\n",out_cmd->md5);
			if (memcmp(out_cmd->md5,get_cmd->md5,32)!=0)
			{
				remove(out_cmd->atgs);
				logwrite("client md5:%s,server md5:%s");
			}
		}
		break;
	case FTP_CMD_QUIT:
		break;
	case FTP_CMD_CD:
		cdaddcmd(&hostcmd,get_cmd->atgs);
		ret =chdir(get_cmd->atgs);
		if (ret==-1)
		{
			logwrite("perror cd %s",get_cmd->atgs);
		}
		break;
	case FTP_CMD_HOST:
		addcmd(&hostcmd,get_cmd->atgs);
		gethost(hostcmd,out_cmd->data);	
	default:
			break;		
	}
	return out_cmd;
}

int main(int argc, char const *argv[])
{
	int s_fd;
	int c_fd;
	int ret;
	int ret2;
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	struct Msg *msg_send;
	struct Msg *msg_recv;
	msg_send = (struct Msg *)malloc(sizeof(struct Msg));
    msg_recv = (struct Msg *)malloc(sizeof(struct Msg));
	logcreate("./server.txt");
	//1.socket
	s_fd=socket(AF_INET,SOCK_STREAM,0);
	if(s_fd==-1)
	{
		logwrite("perror bind: %s",s_fd);
		exit(-1);
	}
	int on=1;
	if((setsockopt(s_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
	{
		perror("setsockopt failed");
		exit(EXIT_FAILURE);
	}
	//2.bind
	s_addr.sin_family=AF_INET;
	s_addr.sin_port=htons(8989);
	s_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	ret=bind(s_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in));
	if (ret==-1)
	{
		logwrite("perror bind: %s",ret);
		exit(-1);
	}
	//3.listen
	ret2=listen(s_fd,10);
	if (ret2==-1)
	{
		logwrite("perror listen: %s",ret2);
		exit(-1);
	}
	//4.accpet
	int len=sizeof(struct sockaddr);
	c_fd=accept(s_fd,(struct sockaddr*)&c_addr,&len);
		if (c_fd==-1)
		{
			logwrite("perror accpet: %s",c_fd);
			exit(-1);
		}
	
	struct  password dl;
	char name[64];
	char passw[64];
	ret=recv(c_fd,&dl,sizeof(struct password),0);
	logwrite("nmae:%s  pass%s\n",dl.name,dl.pass);
	FILE *fd=fopen("passw.txt","r");
	if (NULL!=fd)
	{
		fscanf(fd,"%s %s",name,passw);
		fclose(fd);
	}
	if (strcmp(name,dl.name)!=0||strcmp(passw,dl.pass)!=0)
	{
		dl.cmd=FTP_CMD_ERROR;
	}
	ret=send(c_fd,&dl,sizeof(struct password),0);
	if (dl.cmd==FTP_CMD_ERROR)
	{
		return -1;
	}


	while(1)
	{	

		memset(msg_send,0,sizeof(struct Msg));
		memset(msg_recv,0,sizeof(struct Msg));
		ret=recv(c_fd,msg_recv,sizeof(struct Msg),0);
		logwrite("perror recv: %d\n",ret);
		msg_send=chuli(msg_recv,msg_send);

		ret=send(c_fd,msg_send,sizeof(struct Msg),0);
		logwrite("perror send: %d\n",ret);
		if (msg_recv->cmd==FTP_CMD_QUIT)
		{
			printf("client quit\n");
			logwrite("client quit\n");
			break;
		}
	}
	close(s_fd);
	logout();
	return 0;
}

client.c 用户端

#include 
#include  "log.h"
#include          
#include 
#include 
#include 
#include 
#include 
#include "msg.h"
#include "util.h"

struct Msg *lianjiemingling(char *buf,struct Msg *remsg)//
{
	
	char *get;
	get=strstr(buf," ");
	while(1)
	{
		if (NULL==get|| *get=='\0')
		{
			break;
		}
		get+=1;
		if ( *get!=' ')
		{
			break;
		}
	}
	strncpy(remsg->atgs,get,strlen(get)-1);	
	return remsg;	
}

int get_cmd(char *buf,struct Msg * remsg)
{
	FILE *f=NULL;
	int ret;
	long chang;
	if (memcmp(buf,"ls",2)==0)
	{
	   	strcpy(remsg->atgs,buf);
	   	return 0;
	}
	else if (memcmp(buf,"get",3)==0)
	{
	   	remsg=lianjiemingling(buf,remsg);
	   	return 1;
	}
	else if (memcmp(buf,"put",3)==0)
	{
		remsg=lianjiemingling(buf,remsg);
		get_md5(remsg->atgs,remsg->md5);
		logwrite("yuan md5:%s\n",remsg->md5);
		chang=get_length(remsg->atgs);
		if (chang==-1||chang>sizeof(remsg->data))
		{
			logwrite("perror get_length:%ld",chang);
			return -1;
		}
		f=fopen(remsg->atgs,"r");
		logwrite("perror get : %s\n",remsg->atgs);
		if (NULL!=f)
		{
			ret=fread(remsg->data,1,chang,f);
			logwrite("perror get read: %s",remsg->data);
			remsg->datalen=ret;
			fclose(f);
		}
	   	return 2;
	}
	else if (memcmp(buf,"cd",2)==0)
	{
		remsg=lianjiemingling(buf,remsg);
	   	return 4;
	}
	else if (memcmp(buf,"quit",4)==0)
	{
	   	return 3;
	}
	else if (memcmp(buf,"host",4)==0)
	{
		strcpy(remsg->atgs,buf);
		return 6;
	}
	else 
	{
	   	return 5;

	}	

    
}


void chuli(struct Msg * get_cmd,struct Msg *out_cmd)
{
	FILE *fd=NULL;
	int ret;
	switch(get_cmd->cmd)
	{
	case FTP_CMD_LS:
		printf("%s\n", get_cmd->data);
		break;
	case FTP_CMD_GET:	
		fd=fopen(get_cmd->atgs,"w");
		if(fd!=NULL)
		{
			ret=fwrite(get_cmd->data,1,get_cmd->datalen,fd);

			fclose(fd);
			get_md5(out_cmd->atgs,out_cmd->md5);
			logwrite("xian md5:%s\n",out_cmd->md5);
			if (memcmp(out_cmd->md5,get_cmd->md5,32)!=0)
			{
				remove(out_cmd->atgs);
				logwrite("client md5:%s,server md5:%s");
			}
		
		}
		break;
	case FTP_CMD_PUT:
		break;
	case FTP_CMD_QUIT:
	case FTP_CMD_CD:
	case FTP_CMD_HOST:
		printf("%s\n", get_cmd->data);
		break;
	default:
		break;
	}

}


int main(int argc, char const *argv[])
{
	int c_fd;
    enum FTP_CMD cmd;
    int	ret;
	struct sockaddr_in c_addr;
	int con;

	logcreate("./client.txt");

	struct Msg *msg_send;
	struct Msg *msg_recv;
	msg_send = (struct Msg *)malloc(sizeof(struct Msg));
    msg_recv = (struct Msg *)malloc(sizeof(struct Msg));
	c_fd=socket(AF_INET,SOCK_STREAM,0);
	if (c_fd==-1)
	{
		logwrite("perror connect: %s",c_fd);
		exit(-1);
	}

	c_addr.sin_family=AF_INET;
	c_addr.sin_port=htons(8989);
	c_addr.sin_addr.s_addr=htonl(INADDR_ANY);



	con=connect(c_fd,(struct sockaddr*)&c_addr,sizeof(struct sockaddr));
	if (con==-1)
	{
		logwrite("perror connect: %d",con);
		exit(-1);
	}

	struct password dl;
	printf("name:");
	scanf("%s",dl.name);
	printf("pass:");
	scanf("%s",dl.pass);
	logwrite("nmae:%s  pass%s\n",dl.name,dl.pass);
	ret=send(c_fd,&dl,sizeof(struct password),0);
	logwrite("perror send: %d\n",ret);
	ret=recv(c_fd,&dl,sizeof(struct password),0);
	logwrite("perror recv: %d\n",ret);

	if (FTP_CMD_ERROR==dl.cmd)
	{
		printf("name or pass error\n");
		return -1;
	}
	while(1)
	{
		char buf[256];
		memset(msg_send,0,sizeof(struct Msg));
		memset(msg_recv,0,sizeof(struct Msg));
        // 等待用户输入
        fgets(buf,sizeof(buf),stdin);
        logwrite("get:%s",buf);
        // buf转为FTP_CMD
        cmd = get_cmd(buf,msg_send);
        logwrite("cmd %d\n", cmd);		
		msg_send->cmd=cmd;
		ret=send(c_fd,msg_send,sizeof(struct Msg),0);
		logwrite("perror send: %d\n",ret);
		ret=recv(c_fd,msg_recv,sizeof(struct Msg),0);
		logwrite("perror recv: %d\n",ret);
		chuli(msg_recv,msg_send);
		if (cmd==FTP_CMD_QUIT)
		{
			printf("end\n");
			break;
		}
	}
	
	logout();
	close(c_fd);
	return 0;
}

ftplink.c 链表

#include 
#include 
#include 

struct host
{
	char cmd[32];
	struct host *pnext;
};
void addcmd(struct host **head,char *buf)
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	strcpy(nope->cmd,buf);
	nope->pnext=*head;
	*head=nope;
	
}
void putaddcmd(struct host **head,char *buf)
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	char but[32]="put ";
	strcat(but,buf);
	strcat(but,"\n");
	strcpy(nope->cmd,but);
	nope->pnext=*head;
	*head=nope;
	
}
void getaddcmd(struct host **head,char *buf)
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	char but[32]="get ";
	strcat(but,buf);
	strcat(but,"\n");
	strcpy(nope->cmd,but);
	nope->pnext=*head;
	*head=nope;
	
}
void cdaddcmd(struct host **head,char *buf)
{
	struct host* nope;
	nope=(struct host*)malloc(sizeof(struct host));
	char but[32]="cd ";
	strcat(but,buf);
	strcat(but,"\n");
	strcpy(nope->cmd,but);
	nope->pnext=*head;
	*head=nope;
}
void  print(struct host *p)
{	
	struct host* head=p;
	while(head!=NULL)
	{
		printf("%s",head->cmd);
		head=head->pnext;
	}
}

void gethost(struct host *p,char *buf)
{
	struct host* head=p;
	while(head!=NULL)
	{
		strcat(buf,head->cmd);
		head=head->pnext;
	}
}

ftplink.h

#ifndef _FTPLINK_H
#define _FTPLINK_H


void addcmd(struct host **head,char *buf);

void getaddcmd(struct host **head,char *buf);

void putaddcmd(struct host **head,char *buf);

void cdaddcmd(struct host **head,char *buf);

void print(struct host *p);


void gethost(struct host *p,char *buf);


#endif

msg.c 公用结构体

#ifndef _FTOLINK_H
#define _FTPLINK_H

#define SERVER_PORT 8989


enum FTP_CMD
{
	//ls 
	FTP_CMD_LS=0,
	//get 下载
	FTP_CMD_GET=1,
	//put 上传 
	FTP_CMD_PUT=2,
	//quit 断开连接
	FTP_CMD_QUIT=3,
	//cd 切换服务端目录
	FTP_CMD_CD=4,
	//登录错误
	FTP_CMD_ERROR=5,

	FTP_CMD_HOST=6
};
struct password
{
	enum  FTP_CMD cmd;

	char name[64];

	char pass[64];
};
struct Msg{
	//命令 
	enum  FTP_CMD cmd;

	//命令的参数 get test.c
	char atgs[32];
	//md5
	char md5[64];

	int datalen;
	//test.c打的内容长度未知
	char data[5000];
};
#endif

util.c md5和文件长度函数

#include 
#include 


long get_length(char *format)
{
	FILE *fd=NULL;
	fd=fopen(format,"r");
	if (NULL!=fd)
	{
		fseek(fd,0,SEEK_END);
		long length=ftell(fd);
		fclose(fd);
		return  length;
	}
	return -1;
}

void get_md5(char *format,char *md5)
{
	FILE *fd=NULL;
	char fmat[64];
	char fmot[64];
	sprintf(fmat,"md5sum %s",format);
	fd=popen(fmat,"r");
	if (NULL!=fd)
	{
		int ret=fread(fmot,1,64,fd);
		if (ret!=-1)
		{
			strncpy(md5,fmot,32);	
		}
		fclose(fd);
	}
	else
	{
		perror("");
	}
}

util.h

#ifndef _UNTIL_H
#define _UNTIL_H
long get_length(char *format);
void get_md5(char *format,char *md5);
#endif

这次的项目对于我来说是一个新的挑战,之前我从未写过这么多的代码,因此遇到的困难也变得多了,其中最主要的就是再打开文件后没有用完就关闭的习惯,导致后面再执行fclose是会造成内存溢出的错误,问题困扰了我一整个下午,最后在询问老师后发现了这个问题,对此要引以为戒。

你可能感兴趣的:(在linux内实现FTP传输)