当前位置:网站首页>作业8.10 TFTP协议 下载功能
作业8.10 TFTP协议 下载功能
2022-08-11 03:06:00 【不知名大学生M】
TFTP协议 下载功能
实现代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
//打印错误新的宏函数
#define ERR_MSG(msg) do{\ fprintf(stderr, " __%d__ ", __LINE__);\ perror(msg);\ }while(0)
int main(int argc, const char *argv[])
{
if(argc < 4)
{
fprintf(stderr, "请输入IP port\n");
return -1;
}
//将获取到的端口号字符串,转换成整形
int port = atoi(argv[2]);
//创建报式套接字
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//绑定客户端自身的地址信息结构体 ---> 非必须绑定
//填充服务器的IP地址以及端口号 -->因为客户端要主动发送数据包给服务器
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = inet_addr(argv[1]);
struct sockaddr_in rcv_addrmsg; //存储接收到的数据包来自哪里
socklen_t addrlen = sizeof(rcv_addrmsg);
char buf[128] = ""; //读写请求
char buf2[1024]= ""; //数据包
char buf3[16]=""; //ACK
char *ptr=buf;
short int* pa =(short int*)ptr;
*pa=htons(1); //读写请求的操作码
char *pb=ptr+2; //读写请求的文件名
strcpy(pb,"5.png");
char *pc =pb+strlen(pb);
char *pd=pc+1;
strcpy(pd,"octet"); //读写请求的模式
size_t size=2+strlen(pb)+1+strlen("octet")+1; //读写请求长度
//将数据包发送给服务器,所以地址信息结构体需要填服务器的信息
if(sendto(sfd, buf,size,0,(struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
//printf("sendto success\n");
short int num=1; //块编号
ssize_t res; //数据包成功读取的字节数
int fd=open(argv[3],O_WRONLY|O_TRUNC|O_CREAT,0777); //打开指定文件
if(fd<0)
{
ERR_MSG("open");
return -1;
}
while(1)
{
bzero(buf2, sizeof(buf2)); // 数据包清空
//接收服务器发送过来的数据包
if((res=recvfrom(sfd, buf2, sizeof(buf2), 0, (struct sockaddr*)&rcv_addrmsg,&addrlen))< 0)
{
ERR_MSG("recvfrom");
return -1;
}
char *ptr2=buf2;
short int *err;
if(ntohs(*(err=(short int*)ptr2))==5) //操作码等于5,ERROR
{
printf("error:%s\n",(char*)(err+2)); //打印差错信息
return -1;
}
//操作码不为5,即为3,是数据包,ptr2指向数据包首地址
write(fd,ptr2+4,res-4); //数据包的数据写入文件
short int *pa2=(short int*)ptr2; //获取服务器发过来的块编号
if(ntohs(*(pa2+1))!=num) //比较块编号是否相同,即顺序正确
{
continue;
}
num++;
bzero(buf3, sizeof(buf3)); //清空ACK
char *ptr3=buf3; //ACK首地址
short int* pa3=(short int*)ptr3;
*pa3=htons(4); //ACK操作码
*(pa3+1)=*(pa2+1); //ACK块编号
//将ACK发送给服务器
if(sendto(sfd, buf3,4,0,(struct sockaddr*)&rcv_addrmsg, addrlen) < 0)
{
ERR_MSG("sendto");
return -1;
}
if(res<516) //数据包里的数据小于512字节
{
break; //退出循环
}
}
printf("下载完成\n");
//关闭套接字
close(sfd);
return 0;
}
运行结果
服务器
IP地址:192.168.31.22
端口:69
从服务器下载文件5.png




边栏推荐
- postgresql ilike create function
- What does the sanction of the mixer Tornado mean for the DeFi market?
- 代码 Revert 后再次 Merge 会丢失的问题,已解决
- CC0 与商业 IP:哪种模式更适合 NFT?
- 【LeetCode】Day112-重复的DNA序列
- OpenCV founder: Open source must not be completely free!
- 成都纸质发票再见!开住宿费电子发票即将全面取代酒店餐饮加油站发票
- The negative semantic transformation layer
- 基于改进YOLOv5轻量化的烟火检测
- 获取链表长度
猜你喜欢
随机推荐
Ninjutsu_v3_08_2020-安全渗透系统安装
redis学习五redis的持久化RDB,fork,copyonwrite,AOF,RDB&AOF混合使用
Docker 链接sqlserver时出现en-us is an invalid culture错误解决方案
2022年G1工业锅炉司炉题库及模拟考试
重庆纸质发票再见!开住宿费电子发票即将全面取代酒店餐饮加油站发票
调试技巧总结
聊聊对RPC的理解
IDE compilation error: Dangling metacharacter
MongoDB 基础了解(二)
Idea (优选)cherry-pick操作
JS-DOM element object
Realization of vending machine function based on FPGA state machine
Talk about the understanding of RPC
What does the sanction of the mixer Tornado mean for the DeFi market?
ESP32的环境配置(arduino arduino2.0 VScode platform哪个好用?)
The problem that Merge will be lost again after code Revert has been solved
【LeetCode】Day112-repetitive DNA sequence
qtcreator调试webkit
leetcode: 358. Reorder strings at K distance intervals
CC0 vs. commercial IP: which model is better for NFTs?