基于UDP的TFTP文件传输-实现网盘上传下载功能

数据传输模式:octet(二进制模式)

#include<head.h>
char* down_up_request(char* buf,char* filename,int rw,int sockfd,struct sockaddr_in in);
int download(struct sockaddr_in in,char* filename,char* buf,int sockfd);
int upload(struct sockaddr_in in,char* filename,char* buf,int sockfd);
int main(int argc, const char *argv[])
{
	/***********************************
	基于UDF的TFTP文件传输,实现网盘功能
	***********************************/
	/**********客户端代码**************/
	//创建套接文件
	int rtsocket=socket(AF_INET,SOCK_DGRAM,0);
	if(rtsocket==-1){
		perror("socket");
		return -1;
	}
	else{
		printf("套接文件创建成功\n");
	}
	//绑定客户端端口与IP
	struct sockaddr_in cin;
	char* cip="192.168.176.130";
	uint16_t cport=8888;
	cin.sin_family=AF_INET;
	cin.sin_port=htons(cport);
	cin.sin_addr.s_addr=inet_addr(cip);
	int rtbind=bind(rtsocket,(struct sockaddr*)&cin,sizeof(cin));
	if(rtbind==0){
		printf("与客户端绑定成功\n");
	}
	else if(rtbind==-1){
		perror("bind");
		return -1;
	}
	//数据收发
	/*填充服务器地址与端口信息*/
	struct sockaddr_in sin;
	char* sip="192.168.118.161";
	uint16_t sport=69;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(sport);
	sin.sin_addr.s_addr=inet_addr(sip);
	/*********************************/
	char data[516]={0};
	char filename[128]={0};
	printf("*******1<download>*******\n");
	printf("*******2<upload>*********\n");
	printf("*******3<exit>***********\n");
	while(1){
		int option=0;
		printf("please choose option:");
		scanf("%d",&option);
	if(option<1&&option>3){
		printf("enter error,please reenter\n");
		scanf("%d",&option);
	}
		switch(option){
		case 1 :
			{
				printf("please enter download filename:");
				scanf("%s",filename);
				getchar();
				char* rt=down_up_request(data,filename,1,rtsocket,sin);
				download(sin,filename,rt,rtsocket);
			}
			break;
		case 2:
			{
				printf("please enter upload filename:");
				scanf("%s",filename);
				getchar();
				char* rt=down_up_request(data,filename,2,rtsocket,sin);
				upload(sin,filename,rt,rtsocket);
			}
			break;
		case 3: 
			{
				goto END;

			}
			break;
		}
	}
END:
	close(rtsocket);
	return 0;
}
//下载或上传请求
char* down_up_request(char* buf,char* filename,int rw,int sockfd,struct sockaddr_in in){
	short* p1=(short*)buf;
	*p1=htons(rw);//rw操作码转为网络字节序
	char* p2=buf+2;
	strcpy(p2,filename);//存入要下载的文件名
	char* p3=p2+strlen(p2)+1;
	strcpy(p3,"octet");//设置操作模式
	int size=2+sizeof(p2)+1+sizeof(p3)+1;
	ssize_t rtsendto=sendto(sockfd,buf,size,0,(struct sockaddr*)&in,sizeof(in));
	if(rtsendto==-1){
		perror("sendto");
		return NULL;
	}
	else{
		printf("发送请求成功\n");
	}
	return buf;
}
//下载
int download(struct sockaddr_in in,char* filename,char* buf,int sockfd){
	int fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
	if(fd==-1){
		perror("open");
		return -1;
	}
		short num=0;
		socklen_t addrlen=sizeof(in);
		while(1){
		bzero(buf,sizeof(buf));
		ssize_t rtrecvfrom=recvfrom(sockfd,buf,516,0,(struct sockaddr*)&in,&addrlen);//循环接收数据
		if(rtrecvfrom==-1){
			perror("recvfrom");
			return -1;
		}
		else{
			printf("reading......\n");
		}
		if(buf[1]==3){//判断是否是数据包
			if(*(short*)(buf+2)==htons(num+1)){//确认块编号接发是否一致
				num++;
				if(rtrecvfrom-4==512){//数据包后512字节为数据
					ssize_t rtwrite=write(fd,buf+4,rtrecvfrom-4);
					if(rtwrite<0){
						printf("write error\n");
						break;
					}
				}
				char ACK[4]={0};
				short *p=(short*)ACK;
				*p=htons(4);
				short *p1=(short*)(ACK+2);
				*p1=htons(num);
				ssize_t rtsendto=sendto(sockfd,ACK,4,0,(struct sockaddr*)&in,addrlen);//写入成功,向服务器发送ACK,确认
				if(rtsendto==-1){
					perror("sendto");
					return -1;
				}
				if(rtrecvfrom<516){//读取小于516说明已经读取结束
					ssize_t rtwrite=write(fd,buf+4,rtrecvfrom-4);
					if(rtwrite<0){
						printf("write error\n");
						break;
					}
					printf("end of download\n"); 
					close(fd);  
					break;
				}
			}
		} 
		else if(buf[1]==5){ //错误信息
			printf("error:%s\n",buf+4);
			close(fd);
			return -1;
		}
	}
}
//上传
int upload(struct sockaddr_in in,char* filename,char* buf,int sockfd){
    int fd=open(filename,O_RDONLY);
    if(fd==-1){
        printf("file don't exist\n");
        return -1;
    }
        short num=0;
        socklen_t addrlen=sizeof(in);
        while(1){
        bzero(buf,sizeof(buf));
        ssize_t rtrecvfrom=recvfrom(sockfd,buf,4,0,(struct sockaddr*)&in,&addrlen);//循环接收服务器确认消息
        if(rtrecvfrom==-1){
            perror("recvfrom");
            return -1;
        }
        else{
            printf("ready upload....\n");
        }
	//	printf("ACK=%d\n",ntohs(*(short*)(buf+2)));//查看第一次发过来的ack
	//	解析服务器数据,读取并发送数据包给服务器
        if(buf[1]==4){//判断服务器是否发来ACK
            if(*(short*)(buf+2)==htons(num)){//确认块编号接发是否一致,从0开始
                ssize_t rtread=read(fd,buf+4,512);
				printf("uploading.......\n");
			//	printf("rtread=%ld\n",rtread);
                short *p=(short*)buf;
                *p=htons(3);//修改为数据包,服务器识别数据包下载数据
				num++;//ACK块编码确认+1给服务器确认
                short *p1=(short*)(buf+2);
                *p1=htons(num);
                ssize_t rtsendto=sendto(sockfd,buf,rtread+4,0,(struct sockaddr*)&in,addrlen);//将上传的文件以每512字节发送给服务器,并发送ACK确认
                if(rtsendto==-1){
                    perror("sendto");
                    return -1;
                }
                if(rtread<512){//读取小于512说明上传的文件已经读取完毕
                    printf("upload success\n");
                    close(fd);
                    break;
                }
            }
        }
        else if(buf[1]==5){ //错误信息
            printf("error:%s\n",buf+4);
            close(fd);
            return -1;
        }
    }
}

  • 16
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值