在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配置文 阅读详情

相关推荐

【UE5】Vosk插件实战:离线语音识别与TTS朗读全流程解析

本文详细解析了如何在UE5中利用Vosk插件实现离线实时语音转文字功能。从环境配置、插件与模型准备,到核心C++组件封装与蓝图系统搭建,提供了完整的实战教程。重点解决了离线语音识别在游戏开发中的延迟、隐私和网络依赖问题,并演示了从语音识别到TTS朗读的完整交互闭环,为开发安全、实时的语音交互应用提供可靠方案。

weixin_29021291的博客 509

Linux FTP服务

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

qq_60182534的博客 3192

CANopen中SDO、PDO字典以及COB-ID理解

CANopen SDO PDO

sunarmy的专栏 2万+

几个Linux下FTP client

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

richu123的专栏 8200

RIGOL DS1102E示波器新手必看:从开机到捕获第一个波形的5分钟指南

本文为RIGOL DS1102E示波器新手提供了一份快速上手指南。内容涵盖从开机、探头校准到捕获第一个波形的完整流程,重点解析了触发设置、自动测量等核心操作,并指出了探头衰减比设置等常见误区,帮助用户快速掌握这款经典数字示波器的基本使用方法。

dream的博客 739

1.4 《SST通用技术规范》整体框架与核心条款解读

本小节以**GB/T《电力电子变压器通用技术要求》**(固态变压器SST核心通用规范)为核心依据,结合电力电子变压器技术特性与工程应用边界,系统解析规范的整体章节框架、层级逻辑与强制性/推荐性核心条款,明确规范与传统工频变压器标准的差异,为SST拓扑设计、性能验证、出厂检验与工程落地提供标准化依据。全文以标准原文、期刊文献数据与试验规范为支撑,无主观推演与感性表述。

技术工作者 1679

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

ftp

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

python解析通达信dat与blk数据文件【附源码】

本文介绍了一个完整的通达信金融数据解析器项目,该项目攻克了通达信专有二进制文件格式解析的技术难题。项目采用模块化架构,从基础二进制解析到增强数据分类,最终实现智能语义化列名生成,形成完整的数据处理链路。核心技术包括自适应编码检测、智能数据类型推断和基于业务规则的语义化处理,解决了逆向工程、多编码兼容性等挑战。项目成果显著,解析成功率达100%,数据可读性大幅提升,开发效率提高50%,为量化交易、可视化分析等场景提供了可靠数据支持。该方案不仅具备技术创新性,更具有实际工程应用价值,为金融数据分析领域提供了可复

qq_36224726的博客 2687

Linux ftp服务器和客户端解析

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

飞翔de刺猬 5926

TI CC2642R蓝牙5.2模块实战:从零搭建智能门锁原型(附电路图)

本文详细介绍了如何基于TI CC2642R蓝牙5.2模块从零搭建智能门锁原型,涵盖硬件选型、低功耗配置、蓝牙安全交互等关键环节。通过CC2642R的高性能MCU和蓝牙5.2技术,开发者可实现低功耗、高安全性的智能门锁设计,并提供实用的电路图和PCB布局建议。

o5p6q的博客 109

HFSS 3D Layout仿真PCB操作说明

本文介绍一种特别适合PCB这种叠层结构的仿真软件,HFSS 3D Layout既有操作的简便性,又有同3D软件仿真所有的精确性,仿真速度上又比3D软件快很多。

sinat_15150363的博客 3937

Linux--install-ftp server/client

linux install ftp

qq_37233070的博客 497

Linux 下 OpenClaw 安装全记录:从零到一的保姆级图文教程

本文主要介绍了Linux 下 OpenClaw 安装全记录:从零到一的保姆级图文教程,希望能对学习使用OpenClaw 的同学们有所帮助。 文章目录 1. 背景 2. 实战教程 2.1 步骤一 安装Node.js 2.2 步骤二:安装git 2.3 步骤三:安装并配置OpenClaw 2.4 步骤四:配置OpenClaw 2.5 步骤五:配置模型 2.6 步骤六:对话 3. 后续使用步骤 4. 报错解决方案 5. OpenClaw的卸载

weixin_43178406的博客 10万+

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

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

SKMIT的博客 5063

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

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

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

NiKoJJ‘s Blog 1169

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

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、付费专栏及课程。

余额充值