赞
踩
简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输
特点:
是应用层协议
基于UDP协议实现
数据传输模式
octet:二进制模式(常用)
mail:已经不再支持
TFTP通信过程总结
服务器在69号端口等待客户端的请求
服务器若批准此请求,则使用 临时端口 与客户端进行通信。
每个数据包的编号都有变化(从1开始)
每个数据包都要得到ACK的确认,如果出现超时,则需要重新发送最后的数据包或ACK包
数据长度以512Byte传输的,小于512Byte的数据意味着数据传输结束。
- #include "tftp.h"
- int main(int argc, char const *argv[])
- {
- while (1)
- {
- // 菜单
- printf("*******************\n");
- printf("******1:下载*******\n");
- printf("******2:上传*******\n");
- printf("******0:退出*******\n");
- printf("*******************\n");
- int a = -1;
- printf("请输入要进行的功能:");
- scanf("%d", &a);
- switch (a)
- {
- case 1:
- {
- // 调用下载函数
- if (download() == -1)
- {
- perror("下载失败");
- return -1;
- }
- printf("请输入任意字符后按回车键继续...");
- getchar(); // 等待用户输入一个字符
- system("clear"); // 清空终端(在Linux系统中)
- }
- break;
- case 2:
- {
- // 调用上传函数
- if (upload() == -1)
- {
- perror("上传失败");
- return -1;
- }
- printf("请输入任意字符后按回车键继续...");
- getchar(); // 等待用户输入一个字符
- system("clear"); // 清空终端(在Linux系统中)
- }
- break;
- case 0:
- {
- goto END;
- }
- break;
- default:
- printf("请重新输入\n");
- break;
- }
- }
- END:
- return 0;
- }
- #include "tftp.h"
- //定义下载文件函数
- int download()
- {
- // 创建套接字文件
- int cfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (cfd == -1)
- {
- perror("socket error");
- return -1;
- }
- //printf("cfd = %d\n", cfd); // 3
- // 向服务器发送下载请求
- char buf[516] = "";
- short *p1 = (short *)buf; // 操作码
- *p1 = htons(1);
- char *p2 = buf + 2; // 文件名
- printf("请输入要下载的文件名:");
- scanf("%s", p2);
- getchar();
- char *p4 = p2 + strlen(p2) + 1;
- strcpy(p4, "octet");
- int size = 2 + strlen(p2) + strlen(p4) + 2; // 请求包总长度
-
- // 将请求包发送给服务器
- struct sockaddr_in sin;
- sin.sin_family = AF_INET;
- sin.sin_port = htons(SER_PORT);
- sin.sin_addr.s_addr = inet_addr(SER_IP);
-
- sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));
- printf("请求包发送成功\n");
-
- // 绑定客户端
- struct sockaddr_in cin;
- cin.sin_family = AF_INET;
- cin.sin_port = htons(CLI_PORT);
- cin.sin_addr.s_addr = inet_addr(CLI_IP);
-
- // 打开要写入的文件
-
- int fd = -1;
- if ((fd = open(p2, O_WRONLY | O_CREAT | O_TRUNC, 0664)) == -1)
- {
- perror("open error");
- return -1;
- }
- // 接收数据包
- char msg[516] = "";
- socklen_t len = sizeof(sin);
- while (1)
- {
- int n = recvfrom(cfd, msg, sizeof(msg), 0, (struct sockaddr *)&sin, &len);
- printf("%d\n",n);
- if (n==-1)
- {
- perror("recvfrom error");
- return -1;
- }
- short *p5 = (short *)msg; // 操作码
- short *p6 = (short *)(msg + 2); // 块编号
- char *p7 = msg + 4; // 文件内容
- short num = ntohs(*p5);
- short key = ntohs(*p6);
-
- if (num == 3)
- {
- // 处理数据包
- write(fd, p7, n-4);
- // 发送ACK
- char ack[516] = "";
- short *p8 = (short *)ack; // 操作码
- *p8 = htons(4);
- short *p9 = (short *)(ack + 2); // 块编号
- *p9 = htons(key);
- sendto(cfd, ack, 4, 0, (struct sockaddr *)&sin, sizeof(sin));
- if (n< 516)
- {
- printf("文件下载完毕\n");
- break;
- }
- }
- else if (num == 5)
- {
- printf("error\n");
- break;
- }
- }
- // 关闭文件描述符
- close(cfd);
- close(fd);
- }
- //定义上传文件函数
- int upload()
- {
- // 创建套接字文件
- int cfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (cfd == -1)
- {
- perror("socket error");
- return -1;
- }
- printf("cfd = %d\n", cfd); // 3
- // 向服务器发送上传请求
- char buf[516] = "";
- short *p1 = (short *)buf; // 操作码
- *p1 = htons(2);
-
- char *p2 = buf + 2; // 文件名
- printf("请输入要上传的文件名:");
- scanf("%s", p2);
- getchar();
-
- char *p4 = p2 + strlen(p2) + 1;
- strcpy(p4, "octet");
- int size = 2 + strlen(p2) + strlen(p4) + 2; // 请求包总长度
-
- // 将请求包发送给服务器
- struct sockaddr_in sin;
- sin.sin_family = AF_INET;
- sin.sin_port = htons(SER_PORT);
- sin.sin_addr.s_addr = inet_addr(SER_IP);
- socklen_t len = sizeof(sin);//数据包大小
-
- sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, len);
- printf("请求包发送成功\n");
-
- // 绑定客户端
- struct sockaddr_in cin;
- cin.sin_family = AF_INET;
- cin.sin_port = htons(CLI_PORT);
- cin.sin_addr.s_addr = inet_addr(CLI_IP);
-
- // 打开要上传的文件
- int fd = -1;
- if ((fd = open(p2, O_RDONLY)) == -1)
- {
- perror("open error");
- return -1;
- }
- short n = 0;
- while (1)
- {
- // 等待ACK
- if (recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len) == -1)
- {
- perror("接收ACK失败");
- close(fd);
- return -1;
- }
- // 准备一个要发送的数据包
- char msg[516] = "";
- short *p5 = (short *)msg; // 操作码
- *p5 = htons(3);
- short *p6 = (short *)(msg + 2); // 块编号
-
- *p6 = htons(++n);
- char *p7 = msg + 4; // 文件内容
-
- read(fd, p7, 512);
- int size_msg = 4 + strlen(p7);
-
- // 发送数据包
- sendto(cfd, msg, size_msg, 0, (struct sockaddr *)&sin, len);
- printf("发送成功\n");
-
- // 接收ACK
- char ack[516] = "";
- short *p8 = (short *)ack; // 操作码
- short *p9 = (short *)(ack + 2); // 块编号
- recvfrom(cfd, ack, 4, 0, (struct sockaddr *)&sin, &len);
-
- // 判断是否上传完毕
- if (strlen(p7) < 512)
- {
- printf("文件上传完毕\n");
- break;
- }
- }
- close(cfd);
- close(fd);
- return 0;
- }
- #ifndef TFTP_H
- #define TFTP_H
- #define SER_PORT 69 // 服务器端口号
- #define SER_IP "192.168.0.131" // 服务器ip地址
- #define CLI_PORT 5555 // 客户端端口号
- #define CLI_IP "192.168.0.105" // 客户端地址
- #include<myhead.h>
- //定义下载文件函数
- int download();
- //定义上传文件函数
- int upload();
- #endif
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。