实现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/types.h>
#include<sys/stat.h>
#include<fcntl.h>
//打印错误新的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr, " __%d__ ", __LINE__);\
perror(msg);\
}while(0)
#define N 1000
#define PORT 69 //1024~49151
#define IP "192.168.31.26" //本机IP,用ifconfig查看
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//请求包
char buf[N]="";
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"); //将模式存入
size_t size = 2+strlen(pb)+1+strlen("octet")+1; //求出请求包的长度
//填充服务器的IP地址及端口
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
//发送读写请求
if(sendto(sfd,buf,size,0, (struct sockaddr*)&sin, sizeof(sin))<0)
{
ERR_MSG("sendto");
return -1;
}
printf("send success\n");
struct sockaddr_in rcv; //存储接收到的数据包来自哪里
socklen_t addrlen = sizeof(rcv);
//创建需要下载的文件
int fd=open("./copy.png",O_RDWR|O_TRUNC|O_CREAT,0777);
if(fd<0)
{
ERR_MSG("open");
return -1;
}
printf("open success\n");
unsigned char ack[4];//ack包
unsigned short code=0;//操作码
unsigned short number=1;//块编号或差错码
char text[512]="";//文件内容或差错信息
while(1)
{
//接收数据包
bzero(buf,sizeof(buf));
ssize_t res;
res=recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&rcv,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("rcv success\n");
code=ntohs(*(unsigned short*)buf);//转换操作码
number=ntohs(*(unsigned short*)(buf+2));//转换块编号或差错码
bzero(text,sizeof(text));
if(code==3)
{
if(res==516)
{
write(fd,buf+4,512);
printf("1\n");
}
else if(res<516)
{
write(fd,buf+4,res-4);
printf("传输结束\n");
break;
}
*(unsigned short*)ack=htons(4);
*(unsigned short*)(ack+2)=htons(number);//创建ack包
if(sendto(sfd,ack,4,0,(struct sockaddr*)&rcv,sizeof(rcv))<0) //发送ack包
{
ERR_MSG("sendto");
return -1;
}
printf("sendto success\n");
number++;
}
else if(code==5)
{
printf("错误消息为[%s]\n",text);
return -1;
}
}
close(sfd);
return 0;
}