5.21 TFTP协议客户端实现+思维导图+模拟面试

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>

#define SER_PORT 69
#define PATHMAXLEN 128

char path[PATHMAXLEN];

enum mode_t{
	READ = 1,
	WRITE,
};


void menu(int cfd, struct sockaddr_in* psin, socklen_t addrlen);
void args_verify(int argc, const char *ip);
void net_init(int* pcfd, struct sockaddr_in* psin, const char* ip);
void download(int cfd, struct sockaddr_in* psin, socklen_t addrlen);
void upload(int cfd, struct sockaddr_in* psin, socklen_t addrlen);
void send_ack(int cfd, struct sockaddr_in* psin, socklen_t addrlen, unsigned short seq);

int main(int argc, const char *argv[])
{	
	args_verify(argc, argv[1]);
	int cfd;
	struct sockaddr_in sin;
	socklen_t addrlen = sizeof(sin);
	net_init(&cfd, &sin, argv[1]);
	menu(cfd, &sin, addrlen);
	close(cfd);
	return 0;
}

void net_init(int* pcfd, struct sockaddr_in* psin, const char* ip){
	*pcfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(-1 == *pcfd){
		perror("socket");
		exit(EXIT_FAILURE);
	}

	psin->sin_family = AF_INET;
	psin->sin_port = htons(SER_PORT);
	psin->sin_addr.s_addr = inet_addr(ip);
}


void menu(int cfd, struct sockaddr_in* psin, socklen_t addrlen){
	while(1){
	//	system("clear");
		puts("Welcome to tftp client");
		puts("author: Jerry");
		puts("Options:");
		puts("① Download");
		puts("② Upload");
		puts("③ Quit");
		printf(">> ");
		char ch;
		scanf("%c", &ch);
		while(getchar() != '\n');
		switch(ch){
			case '1':
			case 'd':
			case 'D':
				puts("Download:");
				download(cfd, psin, addrlen);
				getchar();
				break;
			case '2':
			case 'u':
			case 'U':
				puts("Upload:");
				upload(cfd, psin, addrlen);
				getchar();
				break;
			case '3':
			case 'q':
			case 'Q':
				puts("Bye!");
				getchar();
				return;
				break;
			default:
				puts("Error: invalid option");
				getchar();
				break;
		}
	}
}

void args_verify(int argc, const char *ip){
	if(argc < 2){
		puts("Error: argument required");
		goto ERR_ARG;
	}
	else if(argc > 2){
		puts("Error: too many arguments");
		goto ERR_ARG;
	}
	else{
		char* ret = NULL;
		int count = 0;
		char ip_copy[64] = {};
		strcpy(ip_copy, ip);
		do{
			if(ret)
				ret = strtok(NULL, ".");
			else
				ret = strtok(ip_copy, ".");
			count++;
			if(!ret && count < 5 || count > 5)
				goto ERR_IP;
			else if(ret){
				int part = atoi(ret);
				if(part < 0 || part > 255)
					goto ERR_IP;
			}
		}while(ret);
		return;
	}
ERR_IP:
	puts("Error: invalid ip address");
ERR_ARG:
	puts("Usage: tftp_cli <tftp_ser_ip>");
	exit(EXIT_FAILURE);
}


void send_request(int cfd, struct sockaddr_in* psin, socklen_t addrlen, mode_t mode){
	bzero(path, sizeof(path));
	printf("Please enter the filename: ");
	scanf("%s", path);
	char request[137] = {};
	unsigned short* p_short = (unsigned short*)request;
	if(mode == READ)
		*p_short = htons(1);
	else if(mode == WRITE)
		*p_short = htons(2);
	char* p_char = request;
	strcpy(p_char + 2 , path);
	strcpy(p_char + 2 + strlen(path) + 1, "octet");
	printf("cfd = %d, ip:%s, port:%hd\n", cfd, inet_ntoa(psin->sin_addr), ntohs(psin->sin_port));
	sendto(cfd, request, 2 + strlen(path) + 2 + strlen("octet"), 0,
			(struct sockaddr*)psin, addrlen);
}


void download(int cfd, struct sockaddr_in* psin, socklen_t addrlen){
	send_request(cfd, psin, addrlen, READ);

	unsigned short* p_short = NULL;
	char data[516] = {};
	struct sockaddr_in newsin;
	socklen_t newaddrlen = sizeof(newsin);
	unsigned int ret = recvfrom(cfd, data, sizeof(data), 0, (struct sockaddr*)&newsin, &newaddrlen);
	p_short = (unsigned short*)data;
	if(3 == ntohs(*p_short)){// data package
		int fd_w = open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR|S_IWUSR);
		if(-1 == fd_w){
			perror("open");
			exit(EXIT_FAILURE);
		}
		while(ret == 516){
			unsigned short seq = *(p_short + 1);
			write(fd_w, data + 4, ret - 4);
			send_ack(cfd, &newsin, newaddrlen, seq);
			ret = recv(cfd, data, sizeof(data), 0);
			seq = *(p_short + 1);
			printf("ret=%u\n", ret);
			if(ret < 516){
				write(fd_w, data + 4, ret - 4);
				break;
			}
		}
		close(fd_w);
	}
	else if(5 == ntohs(*p_short)){// error package
		unsigned short err_code = ntohs(*(p_short + 1));
		char *err_str = (char *)(p_short + 2);
		printf("Error %hu: %s\n", err_code, err_str);
	}
	return;
}

void upload(int cfd, struct sockaddr_in* psin, socklen_t addrlen){
	send_request(cfd, psin, addrlen, WRITE);

	unsigned short* p_short = NULL;
	char ack[128] = {};
	struct sockaddr_in newsin;
	socklen_t newaddrlen = sizeof(newsin);
	recvfrom(cfd, ack, sizeof(ack), 0, (struct sockaddr*)&newsin, &newaddrlen);
	p_short = (unsigned short*)ack;

	if(4 == ntohs(*p_short)){// ack package
		unsigned short seq = USHRT_MAX, old_seq;
		unsigned int ret;
		char buf[516];
		int fd_r = open(path, O_RDONLY);
		if(-1 == fd_r){
			perror("open");
			exit(EXIT_FAILURE);
		}
		while(1){
			old_seq = seq;
			seq = ntohs(*(p_short + 1));
			p_short = (unsigned short*)buf;
			if(old_seq != seq){
				if(ret < 512)
					break;
				bzero(buf, sizeof(buf));
				*p_short = htons(3);
				*(p_short + 1) = htons(seq + 1);
				ret = read(fd_r, buf + 4, sizeof(buf) - 4);
			}
			sendto(cfd, buf, ret + 4, 0, (struct sockaddr*)&newsin, newaddrlen);
			recv(cfd, ack, sizeof(ack), 0);
						p_short = (unsigned short*)ack;
		}
		close(fd_r);
	}
	else if(5 == ntohs(*p_short)){// error package
		unsigned short err_code = ntohs(*(p_short + 1));
		char *err_str = (char *)(p_short + 2);
		printf("Error %hu: %s\n", err_code, err_str);
	}
	return;
}


void send_ack(int cfd, struct sockaddr_in* psin, socklen_t addrlen, unsigned short seq){
	char ack[4] = {};
	unsigned short* p_short = (unsigned short*)ack;
	*p_short = htons(4);
	*(p_short + 1) = seq;
	sendto(cfd, ack, sizeof(ack), 0, (struct sockaddr*)psin, addrlen);
}

下载文件:

上传文件:

1.项目中如何实现TCP的并发

2.TCP通信过程中的三次握手

3.四次挥手的过程

4.TCP/IP协议分几层?TCP/IP属于哪一层?

5.UDP为什么会丢包?

6.TCP是同步还是异步? 谈谈对同步异步的理解

7.什么是TCP的粘包现象,如何解决?

8.组播和广播的区别?

9.阻塞IO和非阻塞IO的区别?

10.并发与并行的区别?

相关推荐
#欲速则不达#5 小时前
高级I/O
c++·网络协议
中草药z6 小时前
【JavaEE】http/https 超级详解
网络·笔记·网络协议·学习·http·https·计网
物有本木7 小时前
httpsok-v1.17.0-SSL通配符证书自动续签
网络·网络协议·ssl
F_D_Z7 小时前
【解决办法】git clone报错unable to access ‘xxx‘: SSL certificate problem:
网络·git·网络协议·ssl
BUG制造机.8 小时前
TCP --- 确认应答机制以及三次握手四次挥手
网络·网络协议·tcp/ip
无聊看看天T^T8 小时前
网络基础:TCP/IP五层模型、数据在局域网传输和跨网络传输的基本流程、IP地址与MAC地址的简单解析
网络·数据结构·c++·网络协议·tcp/ip·算法
读心悦9 小时前
在 ArkTS 网络请求中,重新封装一下 http 模块
网络·网络协议·http
小灵蛇9 小时前
HTTP Cookie与Session
服务器·网络协议·http
Sun_Sherry13 小时前
FastAPI: websocket的用法及举例
websocket·网络协议·fastapi
eszcx2039413 小时前
ip经过多个服务器转发会网速变慢吗
服务器·网络协议·tcp/ip