TFTP通信过程:
#include <myhead.h>
#define SER_PORT 69
#define SER_IP "192.168.125.13"
int do_download(int cfd,struct sockaddr_in sin){
unsigned short code = 0;
unsigned short num = 0;
unsigned char ack1[4] = "";
ssize_t ret = 0;
char filename[20]="";int size = sprintf(buf,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);
printf("请输入要下载的文件名:");
scanf("%s",filename);
//组下载请求包
//int size = sprintf(buf,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);
char buf[516]="";
int fd;
unsigned short* ptr1 = (unsigned short*)buf;
*ptr1 = htons(1);
char* ptr2 = buf+2;
strcpy(ptr2,filename);
char* ptr4 = ptr2+strlen(filename)+1;
strcpy(ptr4,"octet");
int size = 2+strlen(ptr2)+strlen(ptr4)+2;
//发送下载请求
if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0){
ERR_MSG("sendto");
return -1;
}
socklen_t addrlen = sizeof(sin);
int flag=0;
while(1){
bzero(buf,sizeof(buf));
//接收数据,接收地址信息
if(-1 == (ret = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen)))
ERR_MSG("recvfrom");
if(3 == buf[1]){
//创建文件接收数据文件
if(flag == 0){
fd=open(filename,O_WRONLY | O_CREAT | O_TRUNC,0664);
if(fd<0){
ERR_MSG("fopen");
return -1;
}
flag =1;
}
//可以在本地记录每次收到的包的编号,
//如果本地记录的包的编号与数据包发送回来的快编号不一致,则不做处理
if(htons(num+1) == *(unsigned short*)(buf+2)){
//将数据写入文件
if(-1 == write(fd,buf+4,ret-4))
ERR_MSG("write");
buf[1] = 4;
//发送ACK包
if(-1 == sendto(cfd,buf,4,0,(struct sockaddr *)&sin,sizeof(sin)))
ERR_MSG("sendto");
if(ret-4<512){
printf("文件%s下载完成\n\n",filename);
break;
}
num++;
}
}
else if(5 == buf[1]){
printf("接收出错\n");
return -1;
}
}
close(fd);
return 0;
}
//上传文件
int do_upload(int cfd,struct sockaddr_in sin){
char buf[516] = "";
ssize_t ret = 0;
char filename[50] = "";
printf("请输入要上传的文件名>>>");
scanf("%s",filename);
while(getchar()!=10);
//判断文件是否存在
int fd = open(filename,O_RDONLY);
if(fd<0){
ERR_MSG("open");
return -1;
}
//创建数据包
int size = sprintf(buf,"%c%c%s%c%s%c",0,2,filename,0,"octet",0);
//发送请求
if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0){
ERR_MSG("sendto");
return -1;
}
socklen_t addrlen = sizeof(sin);
unsigned short num = 0;
ssize_t ret_read = 0;
while(1){
//接收数据包
ret = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
if(ret<0){
ERR_MSG("recvfrom");
return -1;
}
//检验ACK
if(4 == buf[1]){
//将文件读取出来
//第一次返回的ACK的编号为0
if(htons(num) == *(unsigned short*)(buf+2)){
//组数据包
num++;
bzero(buf,sizeof(buf));
*(short*)buf = htons(3);
*(short*)(buf+2) = htons(num);
ret_read = read(fd,buf+4,512);
if(ret_read<0){
ERR_MSG("read");
break;
}
//上传数据包
if(sendto(cfd,buf,ret_read+4,0,(struct sockaddr*)&sin,sizeof(sin))<0){
ERR_MSG("sendto");
break;
}
//当数据小于512时结束
if(ret_read<512){
printf("上传成功\n");
return 0;
}
}
}
}
//关闭文件
close(fd);
}
int main(int argc, const char *argv[])
{
//创建报式套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd<0){
ERR_MSG("socket");
return -1;
}
printf("socket create success cfd=%d\n",cfd);
//填充
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
char choose = 0;
while(1){
system("clear");
printf("********************\n");
printf("*******1.下载*******\n");
printf("*******2.上传*******\n");
printf("*******3.退出*******\n");
printf("********************\n");
printf("请输入>>>");
scanf("%c",&choose);
while(getchar()!=10);
switch(choose){
case '1':
do_download(cfd,sin);
break;
case'2':
do_upload(cfd,sin);
break;
case'3':
goto END;
break;
default:
printf("输入错误\n");
break;
}
printf("输入任意字符清屏>>>");
while(getchar()!=10);
}
END:
//关闭套接字
close(cfd);
return 0;
}