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.并发与并行的区别?

相关推荐
一只小鱼儿吖38 分钟前
进程代理单窗口单IP技术:原理、应用与实现
网络·网络协议·tcp/ip
稳联技术39 分钟前
Ethernet IP与Profinet共舞:网关驱动绿色工业的智慧脉动
网络·网络协议·tcp/ip
高兴达1 小时前
RPC框架--实现一个非常简单的RPC调用
网络协议·rpc·firefox
游戏开发爱好者83 小时前
iOS App首次启动请求异常调试:一次冷启动链路抓包与初始化流程修复
websocket·网络协议·tcp/ip·http·网络安全·https·udp
2501_915106323 小时前
频繁迭代下完成iOS App应用上架App Store:一次快速交付项目的完整回顾
websocket·网络协议·tcp/ip·http·网络安全·https·udp
cocologin4 小时前
RIP 技术深度解析
运维·网络·网络协议
GalaxyPokemon5 小时前
RPC-Client模块
网络·网络协议·rpc
DemonAvenger6 小时前
Go语言中的TCP编程:基础实现与最佳实践
网络协议·架构·go
yzx9910138 小时前
关于网络协议
网络·人工智能·python·网络协议
00后程序员张10 小时前
免Mac上架实战:全平台iOS App上架流程的工具协作经验
websocket·网络协议·tcp/ip·http·网络安全·https·udp