作业--day33

2023-12-20 10:10:47

基于UDP的TFTP文件上传

#include <myhead.h>

#define PORT 69
#define IP "192.168.125.59"

int down(const char *);
int up(const char *);

int main(int argc, const char *argv[])
{

	while(1){
		system("clear");
		//打印菜单
		puts("***************功能**************");
		puts("*************1. 下载*************");
		puts("*************2. 上传*************");
		puts("*************3. 退出*************");

		int choose = -1;
		char filename[128] = "";

		scanf("%d", &choose);
		switch(choose){
		case 1:
			{
				printf("输入文件名>>");
				scanf(" %[^\n]", filename);
				if(down(filename) == -1){
					return -1;
				}

			}
			break;
		case 2:
			{
				printf("输入文件名>>");
				scanf(" %[^\n]", filename);
				if(up(filename) == -1){
					return -1;
				}
			}
			break;
		case 3:

			return 0;

		default:
			puts("输入错误");
		}
	}
	
	return 0;
}

int down(const char *filename){

	int cfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(cfd == -1){
		perror("socket error");
		return -1;
	}

	char buf[516];
	bzero(buf, sizeof(buf));
	//设置为下载(读)操作
	buf[1] = 1;
	//将文件名加入协议包中
	strcpy(buf+2, filename);
	
	//模式
	char mod[6] = "octet";

	//将模式字符串加入协议包中
	strcpy(buf+2+strlen(filename)+1, mod);

	//统计协议包字节数总大小
	int size = 2+strlen(filename)+1+strlen(mod)+1;

	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	socklen_t socklen = sizeof(sin);
	if(sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) == -1){
		perror("sendto error");
		return -1;
	}

	puts("请求成功");

	int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);

	while(1){
		
		bzero(buf, sizeof(buf));
		int res = -1;
		if((res = recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &socklen)) == -1){
			perror("recvfrom error");
			return -1;
		}

		if(buf[1] == 3){
			if(res < 516){//若接收字节数小于516则将数据写入后结束下载

				write(fd, buf+4, res-4);
				buf[1] = 4;
				sendto(cfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin));
				break;
			
			}else{
				
				write(fd, buf+4, 512);
				buf[1] = 4;
				sendto(cfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin));

			}
		}else{
			printf("未知错误,错误码: %d\n", buf[3]);
			close(fd);
			close(cfd);
			return -1;
		}
	}

	close(fd);
	close(cfd);
	return 0;
}

int up(const char *filename){

	
	int cfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(cfd == -1){
		perror("socket error");
		return -1;
	}

	char buf[516];
	bzero(buf, sizeof(buf));
	//设置为上传(写)操作
	buf[1] = 2;
	//将文件名加入协议包中
	strcpy(buf+2, filename);
	
	//模式
	char mod[6] = "octet";

	//将模式字符串加入协议包中
	strcpy(buf+2+strlen(filename)+1, mod);

	//统计协议包字节数总大小
	int size = 2+strlen(filename)+1+strlen(mod)+1;

	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	socklen_t socklen = sizeof(sin);
	if(sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) == -1){
		perror("sendto error");
		return -1;
	}

	puts("请求成功");

	int fd = open(filename, O_RDONLY);
	//用于表示传输块的编号
	short block_num = 0;
	//用于操作ACK应答包的数据块的编号
	short * const p = (short *)(buf+2);
	int res = -1;

	while(1){

		recvfrom(cfd, buf, 4, 0, (struct sockaddr *)&sin, &socklen);
		//printf("num = %d, block_num = %d\n", buf[1], block_num);

		if(buf[1] == 4){

			//使用指针p提取数据时需要注意字节序的问题
			if(ntohs(*p) == 0 || block_num == ntohs(*p)){
				buf[1] = 3;
				res = read(fd, buf+4, 512);
				*p = htons(++block_num);
				size = res + 4;
				if(res == 0){
					break;
				}else{
					sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));
				}
			}else{
				buf[1] = 3;
				sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));
			}

		}else{

			printf("未知错误,错误码: %d\n", buf[3]);
			close(fd);
			close(cfd);
			return -1;

		}
	}

	close(fd);
	close(cfd);
	
	return 0;
}

在这里插入图片描述

思维导图

在这里插入图片描述

文章来源:https://blog.csdn.net/qq_39831963/article/details/135092517
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。