在linux内实现FTP传输

从零实现Linux C语言FTP云盘:Socket编程与文件传输实战 文件传输协议(FTP)作为经典的网络应用层协议,其核心在于通过独立的控制连接与数据连接实现可靠的文件交换。理解其工作原理,是掌握网络编程和C/S架构设计的重要基础。在Linux环境下,使用C语言实现FTP服务端,能够深入实践Socket编程、多进程并发、文件I/O及协议解析等底层技术,这对于构建高性能、可控的网络服务具有关键价值。本项目通过实现一个简易的FTP云盘,将上述原理应用于私有轻量文件共享场景,重点解决了被动模式(PASV)连接建立、目录遍历安全防护及二进制文件传输等工程挑战,为C语言学习者和系统开 阅读详情

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 <stdio.h>
#include <stdarg.h> 
#include <stdlib.h>
#include <string.h>
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 <stdio.h>
#include  "log.h"
#include <sys/types.h>         
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#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 <stdio.h>
#include  "log.h"
#include <sys/types.h>         
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#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 <stdio.h>
#include <string.h>
#include <stdlib.h>

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 <stdio.h>
#include <string.h>


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系统和Windows系统之间的文件传输 DHCP和FTP一、FTP的概念二、操作过程 一、 一、FTP的概念 FTP服务——用来传输文件的协议 FTP服务器默认使用TCP协议的20、21端口进行通信 (20端口用于建立数据连接并传输文件数据,21端口用于建立控制连接并传输FTP控制命令) FTP数据连接可以分为主动模式(服务器主动发起数据连接)和被动模式(服务器被动等待书记连接) 二、操作过程 (1)安装 yum install -y vsftpd 查看FTP配置文件 (2)备份(防止改错,因为配置文件没有模板) (3) vim配置文 阅读详情

相关推荐

图像相似度的评价指标 : FID(Fréchet Inception Distance)

FID(Fréchet Inception Distance) 是用来计算真实图像与生成图像的特征向量间距离的一种度量。如果FID值越小,则相似程度越高。最好情况即是FID=0,两个图像相同。 实际计算: 参考链接:https://machinelearningmastery.com/how-to-implement-the-frechet-inception-distance-fid-from-scratch/ # example of calculating the frechet inceptio

weixin_43723625的博客 1万+

Linux FTP服务

FTP服务 一、FTP简介 FTP(File Transfer Protocol,文件传输协议)是Internet中应用广泛的服务之一,主要用提供在Internet上任意计算机之间相互传输文件的机制。 二、FTP概述 FTP(File Transfer Protocol,文件传输协议)是用来在不同类型的计算机之间传输文件的协议。而FTP服务器,是在网络中提供存储文件空间的计算机,应用FTP协议提供服务。用户可以连接到服务器来下载文件,也可以将文件上传到FTP服务器中。因此,FTP服务器方便了用户

qq_60182534的博客 3192

【MDC开发者课程】MDC功能软件-归控算法介绍

规控算法

博客标题不能为空我也没办法 1844

几个Linux下FTP client

File Zilla   文件zilla是一个开源的、跨平台的Linux FTP客户端。File zilla有一个选项卡式用户界面,允许用户查看正在传输的文件的所有细节。文件zilla是在网络上传输较大文件的完美方式,它允许您恢复大于4 GB的文件。它的拖放功能使得通过FTP传输文件变得更加容易。   Fire FTP   Fire ftp允许您在远程站点之间传输文件。它为您提供了最佳...

richu123的专栏 8200

FPGA DMA IP核使用指南

数据传输:支持从源地址到目标地址的数据传输。中断管理:提供中断信号,便于CPU处理传输完成事件。传输控制:支持传输大小、方向和暂停/恢复控制。

weixin_66634995的博客 2428

Gazebo仿真UUV水下机器人:从环境搭建到避障算法实战

本文详细介绍了使用Gazebo仿真平台进行UUV水下机器人开发的全流程,涵盖从环境搭建、uuv_simulator配置、传感器集成到核心避障算法实战。通过搭建水下仿真实验室并实现基于激光雷达数据的反应式避障算法,为水下机器人算法验证与开发提供了高效、低成本的解决方案。

weixin_28840591的博客 263

Linux的FTP安装、使用和配置(FTP客户端管理工具)

ftp

梦想起飞的地方......... 6475

解锁微信小程序Camera组件的隐藏技能:连续扫码背后的逻辑与陷阱

本文深入解析微信小程序Camera组件在连续扫码功能中的技术原理与优化方案,涵盖识别率提升、内存管理策略及典型问题排查。通过实战参数对比和代码示例,帮助开发者解决扫码枪应用中的性能损耗与界面卡顿问题,提升零售、物流等场景的工作效率。

weixin_29019241的博客 490

Linux ftp服务器和客户端解析

文章目录ftp术语是什么工作方式用户授权传输模式ftp服务器ftpdvsftpd安装文件结构运行方式vsftpd配置文件chroot账号登录限制欢迎信息虚拟路径ftp客户端 嵌入式Linux开发过程中需要经常涉及到文件的拷贝,那么使用简单、快捷的应该是ftp服务。ftp服务器一般分为两种:vsftpd和ftpd,下面逐一讲解一下。 ftp术语 是什么 FTP(File Transfer Proto...

飞翔de刺猬 5926

Netty UDP

UDP是一种无连接的协议,它并不在通信双方之间建立连接,而是直接将数据包从发送端发送到接收端。UDP不保证数据包的可靠传输,也不保证数据包的顺序,因此其传输速度通常比TCP快,且系统开销较小。然而,这也意味着UDP在某些情况下可能会丢失数据包或数据包到达的顺序错乱。

王小工小工历程 2025

【功能安全】软件安全架构

目录01 软件安全架构介绍02 软件架构设计模板03 软件架构设计示例 软件架构设计的目的 软件架构设计的原则 软件架构设计输入与输出 软件架构设计的要求 注:软件架构设计和软件安全要求之间的双向可追溯性。软件架构设计原则: 软件架构静态/动态设计(参考秒尼科技术) 软件架构静态设计 软件架构动态设计 软件分层架构设计 软件架构设计安全机制错误探测的安全机制 其中:数据的范围检查指输入输出数据的范围进行检查,例如:在程序中我们可以通过数据范围来排除数据的正确性;合理性检查 例如:使用参

weixin_36460584的博客 511

Linux--install-ftp server/client

linux install ftp

qq_37233070的博客 497

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【Linux】基于FTP协议实现Linux与Windows文件传输

基于FTP协议实现Linux与Winodows实现文件传输,是大学期间的一个小实验。在这里做个总结。

SKMIT的博客 5063

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Linux搭建FTP并安装xrdp,实现Windows系统下利用FileZilla传输文件和远程桌面连接

Linux搭建FTP并安装xrdp,实现Windows系统下利用FileZilla传输文件和远程桌面连接

NiKoJJ‘s Blog 1169

Linux定时任务实现ftp远程文件下载并通过scp传输到其他服务器的shell开发

  场景:公司内部服务器需要定期下载外网服务器提供的文件,但是服务器不能直接与外网交互,故申请一台前置机连外网下载远程文件并传输到服务器上,用shell脚本的方式实现。   因之前没接触过shell脚本开发,所以此次也是学习记录一下自己的开发过程。   1、ftp实现远程文件下载并解压指定文件到指定目录   shell脚本如下: #从FTP上下载文件解压并传输到服务器 #!/bin/bas...

蜡笔灬小鑫 2390

通过ftp实现Ubuntu与Linux嵌入式开发板的文件传输功能

      正在进行一个嵌入式Linux开发板的项目,用到了ftp功能。先简单介绍一下我这边的硬件:PC机和Linux开发板(AM4378);还有软件:PC机下装了虚拟机,Ubuntu的版本是12.04,Linux开发板的内核版本为4.1.18。我的Linux开发板是通过buildroot编译的文件系统,因此在加入ftp功能直接到busybox中配置。如果本身你的开发板已经有了ftpd、ftpge...

qq_38000429的博客 6401

FTP文件传输协议(实现windows与linux文件互传)

FTP文件传输协议(实现windows与linux文件互传) 目录FTP文件传输协议(实现windows与linux文件互传)一、FTP概述二、FTP通信端口三、FTP数据连接四、FTP连接实验详解1、实验环境:虚拟机Centos7,虚拟机Windows10(1)、安装vfstp安装包(2)、设置匿名用户访问的FTP服务(最大权限)(3)、开启服务,关闭防火墙和增强型安全功能(4)、匿名访问测试2、设置本地用户验证访问ftp,并禁止切换到ftp以外的目录(默认登录的根目录为本地用户的家目录) 一、FTP概述

Chenwei的博文 1万+

linux做完sftp端口分离后ftp,Linux 中实现文件传输服务(FTP、SFTP)

????本文将介绍如何在Linux中实现文件传输,这里主要使用FTP、SFTP。????FTP????废话少说,直接进入正题,需要注意,FTP采用Client/Server架构,并且有两个信道(控制信道、数据信道)。????????当Client发起连接时,目标端口为TCP/21 ,Server对其身份验证通过后,建立连接,也就是控制信道,此信道用于Client传输FTP指令,例如ls、cd、ge...

weixin_39765697的博客 259

ftp可以用来和linux传输文件,利用FTP,实现Linux与windows文件互传

3. Serv-U的权限设置比如在左边的面板中选中“yint”用户,则在右边的面板中出现如下图的设置窗口。选“Dir Access”(目录存取权限)标签项,即可设置此用户在它的主目录(此处为“E:\”)下是否对文件拥有“Read”(读)、Write(写)、“Append”(写和添加)、“Delete”(删除)、“Execute”(执行)权限;是否对目录拥有“List”(显示文件和目录的列表)、“C...

weixin_39840153的博客 240

ftp实现BINARY传输命令顺序-linux

为了避免linux平台和window平台之间,采用ascull码传输产生\n和\r出错。 如果想上传一个backup.gz文件,由于这个文件是压缩文件,二进制数据。 所有需要与ftp服务器建立binary流传输方式。 首先需要登入ftp服务器,这边就不多说了。 主要讲与服务器建立连接后发送数据时采用的命令: type I MLST backup.gz pasv stor backup.gz x [这里必须发送x,估计这就是binary流传输命令] 这些命令结束后,就可以开始上传文件数据了。

《我是你的正能量》 3161

快解析Linux搭建FTP服务器:轻松实现文件传输

Linux搭建FTP服务器提供了丰富的配置选项,用户可以根据自己的需求和偏好进行灵活的设置。无论是在本地网络中还是通过互联网,用户可以通过FTP客户端与FTP服务器建立连接,上传和下载文件,实现快速、稳定的文件传输。通过Linux搭建的FTP服务器,管理员可以为每个用户指定特定的访问权限,确保文件的安全性和隐私性。搭建FTP服务器是指在Linux操作系统上配置和设置一个FTP(File Transfer Protocol)服务器,以便其他计算机可以通过FTP协议与该服务器进行文件传输和访问。

asdaddsd的博客 300

Linux FTP云盘系统:轻松实现文件传输

本项目实现了一个基于Linux的FTP云盘系统,采用C语言开发,包含服务端和客户端。主要功能包括:文件列表查看(ls/lls)、目录切换(cd/lcd)、文件上传(put)和下载(get)。服务端通过socket监听客户端请求,使用多进程处理并发连接;客户端通过命令交互实现文件操作。核心功能通过strtok、popen等系统函数实现文件路径解析和进程通信。项目实现了基本的FTP协议功能,为文件传输提供了简洁的命令行界面。系统运行方式为:先启动服务端,客户端通过指定IP和端口连接后进行文件操作。

heavy_D的博客 280

widows系统下使用ftp命令实现与linux之间的文件传输以及相关问题的解决。

本文章是为了帮助第一次使用ftp命令想要实现windows系统与Linux系统之间实现文件传输的初学者,话不多说直奔主题。 前提 想使用ftp命令的前提,是你的Linux已经安装并开启了vsftpd服务,可以输入 which vsftpd 命令查看,如果运行之后显示出相关目录则为已经安装,否则需要安装vsftpd 安装vsftpd的方法: yum -y install vsftpd 等待执行结束之...

Leizi__的博客 648

Linux​不用FTP命令的情况下实现文件交互(SCP命令传输)

分享知识 传递快乐 scp是 secure copy的缩写, scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令。linux的scp命令可以在linux服务器之间复制文件和目录。 scp命令用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。 安装scp yum -y install o...

旷野历程 815

极简教程:5分钟内在Linux上设置FTP服务器,轻松实现文件传输

链接:https://www.cnblogs.com/heyongshen/p/17815627.htmlFTP 介绍FTP是File Transfer Protocol的缩写,译为文件传输协议,是基于CS结构的应用层协议。其主要作用是在网络上的两台计算机之间传输文件。FTP传输层使用的是TCP协议,它有一个很大的特点是采用双端口的工作模式,即客户端和服务端的通信是通过两个通道进行的命令通道用于服...

关注微信公众号【开源Linux】,后台回复『10T』,领取10T学习资源大放送,涵盖Linux、虚拟化、容器、云计算、网络、Python、Go等书籍和视频 1211
上一篇: 超声波测距模块
下一篇: 基于树莓派上实现的智能垃圾桶
ffdsafsd
博客等级 码龄7年 5粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值