TFTP协议实现文件的下载
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
//打印错误消息的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.31.178"
#define PORT 69
#define FILE_NAME "1.png"
#define MODE "octet"
int main(int argc, const char *argv[])
{
//套接字
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//服务器地址信息
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(PORT);
cin.sin_addr.s_addr = inet_addr(IP);
char buf[516] = "";
//读写请求
char* ptr = buf;
short int* pa = (short int*)ptr; //操作码
*pa = htons(1);
char* pb = buf+2; //文件名
strcpy(pb,FILE_NAME);
char* pc = pb+strlen(pb)+1;//模式
strcpy(pc,MODE);
int size = 2+strlen(pb)+1+strlen(pc)+1;
//发送请求包
if(sendto(sfd,buf,size,0,(struct sockaddr*)&cin,sizeof(cin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
int fd = open(FILE_NAME,O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd < 0)
{
ERR_MSG("open");
return -1;
}
char *file = (char*)(pa+2); //指向接收文件的数据的首地址
short int data; //数据包的操作码
short int block; //数据包的块编号
int rec_size; //接收的数据大小
int size_cin = sizeof(cin); //服务器地址信息结构体大小
//循环接收文件数据
while(1)
{
bzero(buf,sizeof(buf));
//分析接收的数据
rec_size = recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&size_cin);
if(rec_size < 0)
{
ERR_MSG("recvfrom");
return -1;
}
//数据包的操作码data
data = ntohs(*pa);
if(data == 5)
{
printf("错误:%s\n",file);
return -1;
}
//操作包的块编号
block = ntohs(*(pa+1));
//写入文件中
if(write(fd,file,rec_size-4) < 0)
{
ERR_MSG("write");
return -1;
}
//文件数据小于512退出,加上前面的4个字节是516
printf("%d\n",rec_size);
if(rec_size < 516)
{
printf("%s下载完成\n",FILE_NAME);
break;
}
//返回的块编号
*pa = htons(4);
sendto(sfd,buf,4,0,(struct sockaddr*)&cin,sizeof(cin));
}
return 0;
}