嵌入式培训经验分享——网络编程小项目(实现ftp协议)

在学习网络结构的知识点之后,我们可以做的小项目有很多,这里我分享一个自己实现的一个网络小项目----实现ftp协议(文件传输协议)。简单的实现从服务器中读取存在的文件名,从服务器中下载文件到当前目录,从自己的客户端实现文件上传到服务器。 

1、服务器serv.c

#include <stdio.h>	 
#include <sys/types.h>          
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include "commen.h"
#include <sys/stat.h>
#include <fcntl.h>

#include <errno.h>
struct pthread_serv_msg{
	pthread_t tid;
	int cli_socket;
};



void *serv_for_client(void *args)
{
	int ret;
	struct pthread_serv_msg *pmsg=args;
	int socket = pmsg->cli_socket;
	struct ftp_msg serv_msg;
	while(1){
		memset(&serv_msg,0,sizeof(serv_msg));
		ret = recv(socket,&serv_msg,sizeof(serv_msg),0);
		if(ret < 0)
		{
			perror("recv err");
			close(socket); free(pmsg);return NULL;
		}else if(ret == 0)
		{
			close(socket); free(pmsg);return NULL;
		}
		//printf("serv got serv_msg:%s\n",rxbuf);
		switch(serv_msg.cmd){
		case 1:  //list   获取当前目录下的内容   readdir()
			{  
				DIR *dir = opendir("./");
				if(dir==NULL)
				{
					perror("file opendir err");
					return NULL;
				}
				int i=0,j=0;
				while(1)
				{
					struct dirent *rent = readdir(dir);
					if(rent==NULL)
					{
						//for(int n=0;n<i;n++)
						//{
							//printf("%s\n",serv_msg.response[n]);
						//}
						serv_msg.len=i;
						break;
					}
					if(strcmp(rent->d_name,".")==0 || strcmp(rent->d_name,"..")==0)
					{
						continue;
					}
					//printf("%6s :%d\n",rent->d_name,rent->d_type);
					strcpy(serv_msg.response[i++],rent->d_name);
					//snprintf(serv_msg.response,sizeof(serv_msg.response),\
							"  %s  %s  ",serv_msg.response,rent->d_name);
					
				}
				
				closedir(dir);
				
				ret = send(socket,&serv_msg,sizeof(serv_msg),0);
				if(ret < 0)
				{
					perror("serv send err");
					return NULL;
				}
				break;
			}
		case 2:
			{
				int fd = open(serv_msg.filename, O_CREAT|O_RDWR,0666);
				if(fd < 0){
					perror("open err");
					return NULL;
				}
				while(1){
					memset(serv_msg.filebuf,0,sizeof(serv_msg.filebuf));
					ret = read(fd,serv_msg.filebuf,sizeof(serv_msg.filebuf)-1);
					if(ret < 0 ){
						perror("read err");
						return NULL;
					}else if(ret ==0){
						//send(socket,&serv_msg,sizeof(serv_msg),0);
						//printf("end of file\n");
						return NULL;
					}
					ret = send(socket,&serv_msg,sizeof(serv_msg),0);
					if(ret < 0)
					{
						perror("serv send err");
						return NULL;
					}
					printf("%s",serv_msg.filebuf);
				}
				ret = close(fd);
				if(ret <0){
					perror("close err");
					return NULL;
				}
				break;
			}
		case 3:
			{
				//创建一个空文件 
				int fd = open(serv_msg.filename, O_CREAT|O_RDWR,0666);
				if(fd < 0)
				{
					perror("open err");
					return NULL;
				}
				while(1)
				{
					memset(&serv_msg,0,sizeof(serv_msg));
					ret = recv(socket,&serv_msg,sizeof(serv_msg),0);
					if(ret < 0)
					{
						perror("recv err");
						return NULL;
					}
					ret  = write(fd,serv_msg.filebuf,strlen(serv_msg.filebuf));
					if(ret < 0 ){
						perror("write err");
						return NULL;
					}
					//如果发现对方最后一次,结束while
					if(ret<sizeof(serv_msg.filebuf))
					{
						printf("upload success\n");
						break;
					}
				}
				ret = close(fd);
				if(ret <0){
					perror("close err");
					return NULL;
				}
				break;
			}
		}
	}
	close(socket);
	 free(pmsg);
	return NULL;
}


int main()
{
	int socket_main = socket(AF_INET,SOCK_STREAM,0);
	if(socket_main < 0)
	{
		perror("socket creat err");
		return -1;
	}
	printf("socket success\n");
	struct sockaddr_in serv_addr;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(10090);
	serv_addr.sin_addr.s_addr = 0;//inet_addr("192.168.3.76");
	
	int ret = bind(socket_main, (struct sockaddr *)&serv_addr  , sizeof(serv_addr));
	if(ret < 0)
	{
		perror("bind err");
		return -3;
	}
	printf("bind success\n");
	struct sockaddr_in cli_addr;
	socklen_t addrlen=sizeof(cli_addr);
	
	struct pthread_serv_msg *pserv_msg=NULL;
	int socket_new;

	ret = listen(socket_main,5);
	if(ret < 0)
	{
		perror("listen err");
		return -3;
	}
	printf("listen......\n");
loop:	
	socket_new = accept(socket_main,(struct sockaddr *)&cli_addr,&addrlen);
	if(socket_new < 0)
	{
		perror("accept err");
		return -3;
	}
	printf("accpet success\n");
	printf("serv accpet client ip=%s port=%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
	
	pserv_msg=malloc(sizeof(*pserv_msg));
	pserv_msg->cli_socket=socket_new;
	pthread_create(&pserv_msg->tid,NULL,serv_for_client,pserv_msg);
	pthread_detach(pserv_msg->tid);
	printf("success link\n");
	goto loop;
	
	close(socket_main);
	return 0;
}

2、客户端cli.c

#include <stdio.h>	 
#include <sys/types.h>          
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include "commen.h"
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <errno.h>
/*
	1.获取服务文件   ./cli.out list 
	2.下载文件		 ./cli.out download filename
	3.上传文件		 ./cli.out upload   filename
*/

struct ftp_msg cli_msg;

int main(int argc,char **argv)
{	
	
	//创建套接字
	int socket_clie = socket(AF_INET,SOCK_STREAM,0);
	if(socket_clie < 0)
	{
		perror("socket creat err");
		return -1;
	}
	printf("socket success\n");
	//与服务器建立联系
	struct sockaddr_in serv_addr;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(10090);
	serv_addr.sin_addr.s_addr = 0;//inet_addr("192.168.3.76");
	int ret = connect(socket_clie,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
	if(ret < 0)
	{
		perror("connect err");
		return -3;
	}
	printf("connect success\n");
	memset(&cli_msg,0,sizeof(cli_msg));
	if( strcmp(argv[1],"list")==0 ){
		memset(&cli_msg,0,sizeof(cli_msg));
		cli_msg.cmd=1;
		//发送指令
		ret = send(socket_clie,&cli_msg,sizeof(cli_msg),0);
		if(ret < 0)
		{
			perror("send err");
			return -3;
		}
		//等待服务器回应
		memset(&cli_msg,0,sizeof(cli_msg));
		ret = recv(socket_clie,&cli_msg,sizeof(cli_msg),0);
		if(ret < 0)
		{
			perror("recv err");
			return -3;
		}
		for(int n=0;n<cli_msg.len;n++)
		{
			printf("%s\n",cli_msg.response[n]);
		}
		//printf("111\n");
	}else if( strcmp(argv[1],"download")==0 ){
		memset(&cli_msg,0,sizeof(cli_msg));
		cli_msg.cmd=2;
		strcpy(cli_msg.filename,argv[2]);
		//发送指令
		ret = send(socket_clie,&cli_msg,sizeof(cli_msg),0);
		if(ret < 0)
		{
			perror("send err");
			return -3;
		}
		//创建一个空文件 
		int fd = open(cli_msg.filename, O_CREAT|O_RDWR,0666);
		if(fd < 0)
		{
			perror("open err");
			return -3;
		}
		while(1)
		{
			memset(&cli_msg,0,sizeof(cli_msg));
			ret = recv(socket_clie,&cli_msg,sizeof(cli_msg),0);
			if(ret < 0)
			{
				perror("recv err");
				return -3;
			}
			ret  = write(fd,cli_msg.filebuf,strlen(cli_msg.filebuf));
			if(ret < 0 ){
				perror("write err");
				return -9;
			}
			//如果发现对方最后一次,结束while
			if(ret<sizeof(cli_msg.filebuf)-1)
			{
				printf("download success\n");
				break;
			}
		}
		ret = close(fd);
		if(ret <0){
			perror("close err");
			return -3;
		}
		
	}else if( strcmp(argv[1],"upload")==0 ){
		memset(&cli_msg,0,sizeof(cli_msg));
		cli_msg.cmd=3;
		strcpy(cli_msg.filename,argv[2]);
		//发送指令
		ret = send(socket_clie,&cli_msg,sizeof(cli_msg),0);
		if(ret < 0)
		{
			perror("send err");
			return -3;
		}
		//打开上传的文件夹
		int fd = open(cli_msg.filename, O_CREAT|O_RDWR,0666);
		if(fd < 0){
			perror("open err");
			return -1;
		}
		while(1){
			memset(cli_msg.filebuf,0,sizeof(cli_msg.filebuf));
			ret = read(fd,cli_msg.filebuf,sizeof(cli_msg.filebuf)-1);
			if(ret < 0 ){
				perror("read err");
				return -1;
			}else if(ret ==0){
				send(socket_clie,&cli_msg,sizeof(cli_msg),0);
				//printf("end of file\n");
				return -1;
			}
			ret = send(socket_clie,&cli_msg,sizeof(cli_msg),0);
			if(ret < 0)
			{
				perror("serv send err");
				return -1;
			}
			//printf("%s",cli_msg.filebuf);
		}
		ret = close(fd);
		if(ret <0){
			perror("close err");
			return -1;
		}
	}else {
		//bug;
		printf("输入的格式有误!!!\n");
		return 0;
	}
	
	return 0;
}

3、头文件commen.c

#ifndef __COMMON_XXX_
#define __COMMON_XXX_
struct ftp_msg {
	char cmd;	 
	char filename[32];	
	char filebuf[128];
	int ret;  
	int len;
	char response[32][32];
	int endfileflag; 
};

#endif 

 在编译服务器的时候需要加入外部库,-lpthread。

客户端执行时需要在后面添加参数:./执行文件 指令名称 文件名。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值