首页 > 代码库 > 基于TCP的TFTP(Trivial File Transfer Protocol,简单文件传输协议) 的c编程实现

基于TCP的TFTP(Trivial File Transfer Protocol,简单文件传输协议) 的c编程实现

我们或许都听到过,TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。

本文就简单的叙述下tftp的小文件传输功能以及客户端对服务器的列表功能。

之前就一直很纳闷,我们经常在网上下载什么东西或者从别处传输一个文件,具体是怎么实现的呢?于是乎,翻查一些资料,加上自己对网络编程的逐步加深,所以功夫不负有心人,还算是大致的完成了下。

本例程实现的功能呢? 就是实现客户端对服务器端提供的文件上传与下载功能,还有对服务器端目录的显示功能,好了,请阅读下面的编程实现部分:


首先是服务器端:



#include<head.h>
typedef struct 
{
	int type;
	int size;
	char mtxt[1024];
}MSG;

#define PUT_FILE   10 
#define GET_FILE   20 
#define LIST_DIR   30 
#define NEXIST_FILE 40 
#define YEXIST_FILE 50

void handler_signal(int signum)
{
	waitpid(-1,NULL,WNOHANG);
	printf("CHild process over!\n");
}

void do_put(int sockfd,MSG *pmsg)
{
	int fd;

	fd = open(pmsg->mtxt,O_WRONLY | O_CREAT | O_TRUNC,0666);
	if(fd < 0){
		fprintf(stderr,"Fail to open %s : %s\n",pmsg->mtxt,strerror(errno));
		exit(EXIT_FAILURE);
	}
	
	if(ftruncate(fd,pmsg->size) < 0)
	{
		perror("Fail to ftruncate");
		exit(EXIT_FAILURE);
	}

	while(1)
	{
		if(recv(sockfd,pmsg,sizeof(MSG),0) <= 0)
			break;
		
		if(pmsg->size == 0)
			break;

		write(fd,pmsg->mtxt,pmsg->size);
	}
	
	return ;
}

int do_get(int sockfd,MSG *pmsg)
{
	int fd;
	struct stat f_info;

	fd = open(pmsg->mtxt,O_RDONLY);
	if(fd < 0){
		fprintf(stderr,"Fail to open %s : %s\n",pmsg->mtxt,strerror(errno));	
		pmsg->type = NEXIST_FILE;
	}
	
	if(fstat(fd,&f_info) < 0)
	{
		perror("Fail to fstat");
		pmsg->type = NEXIST_FILE;
	}
	
	if(pmsg->type == NEXIST_FILE)
	{
		//告诉客户端结果
		send(sockfd,pmsg,sizeof(MSG),0);
		return -1;

	}else{
		pmsg->type = YEXIST_FILE;
		pmsg->size = f_info.st_size;
		send(sockfd,pmsg,sizeof(MSG),0);
	}

	while(1)
	{
		pmsg->size = read(fd,pmsg->mtxt,sizeof(pmsg->mtxt));
		if(send(sockfd,pmsg,sizeof(MSG),0) < 0)
		{
			perror("Fail to send");
			exit(EXIT_FAILURE);
		}

		if(pmsg->size == 0)
			break;
	}

	return 0;
}

int do_list(int sockfd)
{
	DIR *pdir;
	MSG msg;
	struct dirent *pdirent;

	pdir = opendir(".");
	if(pdir == NULL)
	{
		msg.type = NEXIST_FILE;
		send(sockfd,&msg,sizeof(MSG),0);
		return -1;
	}
	
	while ( pdirent = readdir(pdir) )
	{
		if(pdirent->d_name[0] == '.')	
			continue;
		
		msg.type = YEXIST_FILE;
		strcpy(msg.mtxt,pdirent->d_name);
		
		if(send(sockfd,&msg,sizeof(MSG),0) < 0)
		{
			perror("Fail to send");
			exit(EXIT_FAILURE);
		}
	}

	msg.type = NEXIST_FILE;
	if(send(sockfd,&msg,sizeof(MSG),0) < 0)
	{
		perror("Fail to send");
		exit(EXIT_FAILURE);
	}
	
	return 0;
}

void do_client(int connect_fd)
{
	MSG msg;

	while(1)
	{
		if(recv(connect_fd,&msg,sizeof(MSG),0) <= 0)
		{
			perror("Fail to recv");
			exit(EXIT_FAILURE);
		}

		switch(msg.type)
		{
			case PUT_FILE:
				do_put(connect_fd,&msg);
				break;

			case GET_FILE:
				do_get(connect_fd,&msg);
				break;

			case LIST_DIR:
				do_list(connect_fd);
				break;
		}
	}

	exit(EXIT_SUCCESS);
}


int main(int argc, const char *argv[])
{
	int listen_fd;
	pid_t pid;
	int connect_fd;
	struct sockaddr_in server_addr;
	struct sockaddr_in peer_addr;
	socklen_t addrlen = sizeof(struct sockaddr_in);

	if(argc < 3)
	{
		fprintf(stderr,"Usage : %s ip port\n",argv[0]);
		exit(EXIT_FAILURE);
	}

	if(signal(SIGCHLD,handler_signal) == SIG_ERR)
	{
		perror("Fail to signal");
		exit(EXIT_FAILURE);
	}

	listen_fd = socket(AF_INET,SOCK_STREAM,0);
	if(listen_fd < 0){
		perror("Fail to socket");
		exit(EXIT_FAILURE);
	}
	
	server_addr.sin_family = AF_INET;
	server_addr.sin_port   = htons(atoi(argv[2]));
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	if(bind(listen_fd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) < 0)
	{
		perror("Fail to bind");
		exit(EXIT_FAILURE);
	}

	listen(listen_fd,128);
	
	printf("listen ...\n");
	while(1)
	{
		connect_fd = accept(listen_fd,(struct sockaddr *)&peer_addr,&addrlen);
		if(connect_fd < 0){
			perror("Fail to accept");
			exit(EXIT_FAILURE);
		}
		
		printf("------------------------------------------------\n");
		printf("connect_fd = %d\n",connect_fd);
		printf("Port : %d\n",ntohs(peer_addr.sin_port));
		printf("IP   : %s\n",inet_ntoa(peer_addr.sin_addr));
		printf("---------------------------------------------\n");
	
		pid = fork();
		if(pid < 0){
			perror("Fail to fork");
			exit(EXIT_FAILURE);
		}
		
		if(pid == 0)
		{
			close(listen_fd);
			do_client(connect_fd);
		}

		//避免文件描述符号浪费
		close(connect_fd);
	}

	return 0;
}

再来看客户端:


#include <head.h>

typedef struct 
{
	int type;
	int size;
	char mtxt[1024];
}MSG;

#define PUT_FILE 10 
#define GET_FILE 20 
#define LIST_DIR 30 
#define NEXIST_FILE 40 
#define YEXIST_FILE 50

int do_put(int sockfd,char *filename)
{
	int fd;
	MSG msg;
	struct stat f_info;

	fd = open(filename,O_RDONLY);
	if(fd < 0){
		fprintf(stderr,"Fail to open %s : %s\n",filename,strerror(errno));
		return -1;
	}
	
	if(fstat(fd,&f_info) < 0)
	{
		perror("Fail to fstat");
		return -1;
	}

	msg.type = PUT_FILE;
	msg.size = f_info.st_size;
	strcpy(msg.mtxt,filename);
	
	if(send(sockfd,&msg,sizeof(MSG),0) < 0)
	{
		perror("Fail to send");
		exit(EXIT_FAILURE);
	}
	
	while(1)
	{
		msg.size = read(fd,msg.mtxt,sizeof(msg.mtxt));
		if(send(sockfd,&msg,sizeof(MSG),0) < 0)
		{
			perror("Fail to send");
			exit(EXIT_FAILURE);
		}

		if(msg.size == 0)
			break;
	}

	return 0;
}

int do_get(int sockfd,char *filename)
{
	int fd;
	MSG msg;

	msg.type = GET_FILE;
	strcpy(msg.mtxt,filename);
	
	if(send(sockfd,&msg,sizeof(MSG),0) < 0)
	{
		perror("Fail to send");
		exit(EXIT_FAILURE);
	}
	
	//等待服务器端结果:文件存放或不存在
	if(recv(sockfd,&msg,sizeof(MSG),0) <= 0)
	{
		perror("Fail to send");
		exit(EXIT_FAILURE);
	}

	if(msg.type == NEXIST_FILE)
	{
		printf("The get file:%s is not exist!\n",filename);
		return -1;
	}

	fd = open(msg.mtxt,O_WRONLY | O_CREAT | O_TRUNC,0666);
	if(fd < 0){
		fprintf(stderr,"Fail to open %s : %s\n",msg.mtxt,strerror(errno));
		exit(EXIT_FAILURE);
	}
	
	if(ftruncate(fd,msg.size) < 0)
	{
		perror("Fail to ftruncate");
		exit(EXIT_FAILURE);
	}
		
	while(1)
	{
		if(recv(sockfd,&msg,sizeof(MSG),0) <= 0)
			break;
		
		if(msg.size == 0)
			break;

		write(fd,msg.mtxt,msg.size);
	}
	
	return 0;
}

int do_list(int sockfd)
{
	MSG msg;

	msg.type = LIST_DIR;
	if(send(sockfd,&msg,sizeof(MSG),0) < 0)
	{
		perror("Fail to send");
		exit(EXIT_FAILURE);
	}

	while(1)
	{
		if(recv(sockfd,&msg,sizeof(MSG),0) <= 0)
			break; 
		
		if(msg.type == NEXIST_FILE)
			break;

		printf("%s\n",msg.mtxt);
	}

	return 0;
}

int do_task(int sockfd,char *pcmd,char *filename)
{
	if(strncmp(pcmd,"get",3) == 0)
	{
		do_get(sockfd,filename);
	
	}else if(strncmp(pcmd,"put",3) == 0){
		
		do_put(sockfd,filename);	
	
	}else if(strncmp(pcmd,"list",4) == 0){
		
		do_list(sockfd);
	
	}else{
		printf("Invalid cmd : %s\n",pcmd);
		return -1;
	}

	return 0;
}


int main(int argc, const char *argv[])
{
	char buf[1024];
	int sockfd;
	char *pcmd,*pname;
	int connect_fd;
	struct sockaddr_in server_addr;
	
	if(argc < 3)
	{
		fprintf(stderr,"Usage : %s ip port\n",argv[0]);
		exit(EXIT_FAILURE);
	}

	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(sockfd < 0){
		perror("Fail to socket");
		exit(EXIT_FAILURE);
	}
	
	server_addr.sin_family = AF_INET;
	server_addr.sin_port   = htons(atoi(argv[2]));
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) < 0)
	{
		perror("Fail to bind");
		exit(EXIT_FAILURE);
	}
	
	while(1)
	{
		printf(">");
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf) - 1] = '\0';
		
		if(strncmp(buf,"quit",4) == 0)
			break;
	
		pcmd  = strtok(buf," ");
		pname = strtok(NULL," ");
		
		do_task(sockfd,pcmd,pname);
	}

	return 0;
}

或许生活就是这个样子,当你想要去做一件事情的时候,那就认真的去做吧,肯定会成功的,或许我们的现在看起来是多么的狼狈不堪,但是我们都没有嘲笑别人的权利,因为成功的人毕竟是少数,我们不能以常人的思维去判断一个人的价值取向,如果真的想实现我们的梦想,那么此时此刻,就是我们应该认真做事,好好做人的时候了,我坚信当你的事业到达一个程度的时候,你的人格魅力将会自动的提升上去。

O(∩_∩)O~于君共勉


基于TCP的TFTP(Trivial File Transfer Protocol,简单文件传输协议) 的c编程实现