赞
踩
tftp协议概述
简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输
特点:
基于UDP协议实现
数据传输模式
octet:二进制模式(常用)
mail:已经不再支持
TFTP通信过程总结
- 服务器在69号端口等待客户端的请求
- 服务器若批准此请求,则使用 临时端口 与客户端进行通信。
- 每个数据包的编号都有变化(从1开始)
- 每个数据包都要得到ACK的确认,如果出现超时,则需要重新发送最后的数据包或ACK包
- 数据长度以512Byte传输的,小于512Byte的数据意味着数据传输结束
TFTP协议分析
差错码:
0 未定义,差错错误信息
1 File not found.
2 Access violation.
3 Disk full or allocation exceeded.
4 illegal TFTP operation.
5 Unknown transfer ID.
6 File already exists.
7 No such user.
8 Unsupported option(s) requested.
- #include "../header.h"
-
- #define S_IP "192.168.125.30"
- #define S_PORT 69
-
- typedef struct file_header {
- int size;
- char *file_report;
- } file_header_report;
- char buf[516] = "";
- char fileName[128] = {0};
- int sockfd = -1;
- int data_num = 0;
-
- void download_file(struct sockaddr_in *addr);
- void upload_file(struct sockaddr_in *addr);
- void dealerror(short errno);
- file_header_report get_report_RW(short type);
- file_header_report get_report_ACK(short type, short blknumber);
-
- int main(int argc, char const *argv[]) {
- // 服务器地址 ,初始地址用于链接请求,但是不是用于实际数据交互
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(S_PORT);
- addr.sin_addr.s_addr = inet_addr(S_IP);
- char choose = 0;
- while (1) {
- printf("**************************\n");
- printf("******** 1. 下载 *********\n");
- printf("******** 2. 上传 *********\n");
- printf("******** 3. 退出 *********\n");
- printf("**************************\n");
- printf("请输入>>> ");
- choose = getchar();
- while (getchar() != 10) {
- };
- switch (choose) {
- case '1':
- download_file(&addr);
- break;
- case '2':
- upload_file(&addr);
- break;
- case '3':
- exit(EXIT_SUCCESS);
- break;
- default:
- printf("输入错误!请重新输入\n");
- }
- }
- close(sockfd);
- return 0;
- }
- void upload_file(struct sockaddr_in *addr) {
- if (sockfd == -1) { // 判断一下,防止重复创建套接字
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd < 0) {
- perror("socket");
- return;
- }
- }
- // 发送上传请求
- printf("请输入要上传的文件名:\n");
- file_header_report file_report = get_report_RW(2);
- if (access(fileName, F_OK) != 0) {
- printf("文件不存在\n");
- return;
- }
- data_num = 0;
- if (sendto(sockfd, file_report.file_report, file_report.size, 0,
- (struct sockaddr *)addr, sizeof(struct sockaddr)) == -1) {
- perror("1111sendto 数据包");
- return;
- }
- // recv_addr 用于 实际数据交互的地址
- struct sockaddr_in recv_addr;
- socklen_t recv_addr_len = sizeof(recv_addr);
- int read_size = recvfrom(sockfd, buf, 516, 0, (struct sockaddr *)&recv_addr,
- &recv_addr_len);
- short *first_no = (short *)buf;
- short *blk_num = (short *)(buf + 2);
- // 处理报错信息 == 5
- if (ntohs(*first_no) == 5) {
- dealerror(ntohs(*blk_num));
- return;
- }
- if (ntohs(*first_no) == 4) {
- int upload_fd = open(fileName, O_RDONLY);
- if (upload_fd < 0) {
- perror("open");
- return;
- }
- while (1) {
- // 发送数据包
- bzero(buf, sizeof(buf));
- // 拼接数据包
- short *p1 = (short *)buf;
- *p1 = htons(3);
- short *p2 = (short *)(buf + 2);
- *p2 = htons(data_num);
- int file_size = read(upload_fd, buf + 4, 512);
- if (file_size < 0) {
- perror("read");
- exit(1);
- }
- if (sendto(sockfd, buf, file_size + 4, 0,
- (struct sockaddr *)&recv_addr,
- sizeof(recv_addr)) == -1) {
- perror("sendto 数据包");
- exit(1);
- }
-
- bzero(buf, sizeof(buf));
- int read_size_n =
- recvfrom(sockfd, buf, 4, 0, (struct sockaddr *)&recv_addr,
- &recv_addr_len);
- short *first_noe_n = (short *)buf;
- short *blk_nume_n = (short *)(buf + 2);
- // 确认ACK包
- // 编号是否与本地的标号一致,一致的话就进行下一个编号的数据传送
- if (ntohs(*first_noe_n) == 4 && ntohs(*blk_nume_n) == data_num) {
- // 这种情况说明本次上传成功
- data_num++;
- } else {
- printf("上传失败\n");
- if (ntohs(*first_no) == 5) {
- dealerror(ntohs(*blk_num));
- return;
- }
- break;
- }
- // 如果最后一次读取,就结束循环
- if (file_size < 512) {
- printf("上传成功\n");
- break;
- }
- }
- } else {
- printf("上传失败\n");
- }
- }
- // 下载
- void download_file(struct sockaddr_in *addr) {
- if (sockfd == -1) { // 判断一下,防止重复创建套接字
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd < 0) {
- perror("socket");
- return;
- }
- }
-
- // 发送下载请求
- printf("请输入要下载的文件名:\n");
- file_header_report file_report = get_report_RW(1);
- if (sendto(sockfd, file_report.file_report, file_report.size, 0,
- (struct sockaddr *)addr, sizeof(struct sockaddr)) == -1) {
- perror("sendto 数据包");
- return;
- }
- struct sockaddr_in recv_addr;
- socklen_t recv_addr_len = sizeof(recv_addr);
- while (1) {
- // 接收数据包
- // 数据包返回的服务器端地址需要存在recv_addr,因为服务器处理数据的端口并非原来端口,
- // 该地址recv_addr 用于后续的ack包 发送给服务器用于确认
- bzero(buf, sizeof(buf));
- int read_size = recvfrom(sockfd, buf, 516, 0,
- (struct sockaddr *)&recv_addr, &recv_addr_len);
- int download_fd = open(fileName, O_RDWR | O_CREAT | O_APPEND, 0666);
- if (download_fd < 0) {
- perror("open");
- return;
- }
- short *first_no = (short *)buf;
- short *blk_num = (short *)(buf + 2);
-
- // 处理报错信息 == 5
- if (ntohs(*first_no) == 5) {
- dealerror(ntohs(*blk_num));
- break;
- }
- // 这是数据包 == 3
- if (ntohs(*first_no) == 3) {
- if (read_size > 4) {
- write(download_fd, buf + 4, read_size - 4);
- }
- // 发送ACK
- *first_no = htons(4);
- char newbuf[4] = {0};
- short *p1 = (short *)newbuf;
- *p1 = htons(4);
- short *p2 = (short *)(newbuf + 2);
- *p2 = *blk_num;
- if (sendto(sockfd, newbuf, 4, 0, (struct sockaddr *)&recv_addr,
- sizeof(recv_addr)) == -1) {
- perror("sendtoACK\n");
- }
- printf("发送ACK成功\n");
- if (read_size < 516) {
- printf("下载完成\n");
- break;
- }
- }
- close(download_fd);
- }
- }
- // 处理报错信息
- void dealerror(short errno) {
- int erno = 0;
- switch (errno) {
- case 1:
- printf("File not found");
- break;
- case 2:
- printf("Access violation");
- break;
- case 3:
- printf("Disk full or allocation exceeded");
- break;
- case 4:
- printf("illegal TFTP operation");
- break;
- case 5:
- printf("Unknown transfer lD");
- break;
- case 6:
- printf("File already exists");
- break;
- case 7:
- printf("No such user");
- break;
- case 8:
- printf("Unsupported option(s) requested");
- break;
-
- default:
- break;
- }
- return;
- }
-
- /**
- * @description: 组装请求体数据包
- * @param {short} type 1--- 下载 2---上传
- * @return {*}
- */
- file_header_report get_report_RW(short type) {
- bzero(buf, sizeof(buf));
- fgets(fileName, sizeof(fileName), stdin);
- if (strlen(fileName) > 1) {
- fileName[strlen(fileName) - 1] = '\0';
- }
- short *p1 = (short *)buf;
- *p1 = htons(type);
- char *p2 = buf + 2;
- strcpy(p2, fileName);
- char *p4 = p2 + strlen(p2) + 1;
- strcpy(p4, "octet");
- int size = 2 + strlen(p2) + strlen(p4) + 2;
- file_header_report fh = {size, buf};
- return fh;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。