一、用dup协议,完成tftp协议的下载
1.1 代码
#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>
//打印错误新的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__);\
perror(msg);\
}while(0)
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("创建报式套接字成功\n");
//填充客户端的IP和端口号
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(69);
sin.sin_addr.s_addr = inet_addr("192.168.31.7");
printf("初始化客户端成功\n");
//接收消息
//发送消息
char buf[128] = "";
char* ptr=buf;
short int* pa=(short int*)ptr;
*pa=htons(1);
char* pb=ptr+2;
strcpy(pb,argv[1]);
char* pc=pb+strlen(pb);
*pc=0;
char* pd=pc+1;
strcpy(pd,"octet");
char* pe=pd+strlen(pd);
*pe=0;
size_t size=2+strlen(pb)+strlen(pd)+2;
printf("%ld\n",size);
//发送接收请求
if(sendto(sfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("sendto");
return -1;
}
struct sockaddr_in cin; //存储接收到的数据包来自哪里
socklen_t addrlen = sizeof(cin);
char rev[516]=""; //数据包大小:操作码+块编号+传输数据512
short int i=1; //块编号
char ack[4]=""; //ACK
FILE* fd_w=fopen("./1.png","w"); //创建要下载的文件副本等待写入
while(1)
{
bzero(buf, sizeof(rev));
//初始化
//发送ack
char* ctr=ack;
short int* ra=(short int*)ctr;
*ra=htons(4);
short int* rb=ra+1;
*rb=ntohs(i);
//接收数据包
ssize_t res=recvfrom(sfd, rev, sizeof(rev), 0, (struct sockaddr*)&cin, &addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
//块是否连续
if(ntohs(*(short int*)(rev+2)) != i)
{
continue;
}
//结束条件
if(res<516)
{
fwrite(rev+4,res-4,1,fd_w);
sendto(sfd,ack,sizeof(ack),0,(struct sockaddr *)&cin,addrlen);
break;
}
//正常下载
fwrite(rev+4,res-4,1,fd_w);
if(sendto(sfd,ack,sizeof(ack),0,(struct sockaddr *)&cin,addrlen)<0)
{
ERR_MSG("sendto");
return-1;
}
i++;
}
printf("下载完成\n");
//关闭套接字
close(sfd);
fclose(fd_w);
return 0;
}
2.2 执行结果