tftp协议上传下载
#include
#define SERIP "192.168.125.32"
#define SERPORT 69
//定义下载函数/*********************************************/
int do_download(int cfd,struct sockaddr_in sin)
{
//获取文件文件名
char filename[40] = "";;
printf("请输入需要下载的文件名:\n");
scanf("%s",filename);
getchar();
//以只写的形式打开文件
int wfd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);
if( wfd == -1)
{
perror("open error");
return -1;
}
//组装数据包
char buf[516] = "";
short *p1 = (short *)buf;
*p1 = htons(1);
char *p2 = buf+2;
strcpy(p2,filename);
char *p3 = p2+strlen(p2)+1;
strcpy(p3,"octet");
int len = strlen(p2) + strlen(p3) + 4;
//向服务器发送请求包
sendto(cfd,buf,len,0,(struct sockaddr *)&sin,sizeof(sin));
printf("发送请求包成功\n");
socklen_t socklen = sizeof(sin);
while(1)
{
bzero(buf,sizeof(buf));
//接收服务器返回的数据包或错误码
int res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
//判断服务器返回的操作码是3,代表是 数据包
if(buf[1] == 3)
{
//写入到目标文件
write(wfd,buf+4,res-4);
//发送ACK给服务器
buf[1] = 4;
sendto(cfd,buf,4,0,(struct sockaddr *)&sin,sizeof(sin));
//判断服务器发送的数据包小于512字节,退出循环
if(res < 516)
{
printf("下载完毕!!!\n");
break;
}
}
else if(buf[1] == 5)
{
printf("do_download error:%s\n",buf+4);
return -1;
}
}
//关闭文件描述符
close(wfd);
close(cfd);
return 0;
}
//定义上传函数/***********************************************/
int do_upload(int cfd,struct sockaddr_in sin)
{
//获取文件文件名
char filename[40] = "";;
printf("请输入需要上传的文件名:\n");
scanf("%s",filename);
getchar();
//以只写的形式打开文件
int rfd = open(filename,O_RDONLY);
if( rfd == -1)
{
perror("open error");
return -1;
}
//组装数据包
char buf[516] = "";
short *p1 = (short *)buf;
*p1 = htons(2);
char *p2 = buf+2;
strcpy(p2,filename);
char *p3 = p2+strlen(p2)+1;
strcpy(p3,"octet");
int len = strlen(p2) + strlen(p3) + 4;
//向服务器发送请求包
sendto(cfd,buf,len,0,(struct sockaddr *)&sin,sizeof(sin));
printf("发送请求包成功\n");
socklen_t socklen = sizeof(sin);
unsigned short num = 0;
while(1)
{
bzero(buf,sizeof(buf));
//接收服务器返回的应答包
int res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
if(buf[1] == 4)
{
//填充发送数据包
if(num == ntohs(*(unsigned short*)(buf+2)))
{
buf[1] = 3;
num++;
*(unsigned short*)(buf+2) = htons(num);
int res1 = read(rfd,buf+4,512);
if(res1 == 0)
{
printf("上传完毕\n");
break;
}
//发送数据包给服务器
sendto(cfd,buf,res1+4,0,(struct sockaddr *)&sin,sizeof(sin));
//判断服务器发送的数据包小于512字节,退出循环
}
else
{
printf("上传失败\n");
break;
}
}
else if(buf[1] == 5)
{
printf("do_download error:%s\n",buf+4);
return -1;
}
}
//关闭文件描述符
close(rfd);
close(cfd);
return 0;
}
/**************************** 主函数 *******************************/
int main(int argc, const char *argv[])
{
//创建用于通信的套接字文件,返回文件描述符
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
//可以绑定,也可以不绑定
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SERPORT);
sin.sin_addr.s_addr = inet_addr(SERIP);
//定义一个菜单选项
int menu = -1;
while(1)
{
system("clear");
printf("\t\t======1、下载=====\n");
printf("\t\t======2、上传=====\n");
printf("\t\t======3、退出=====\n");
printf("请输入选项:");
scanf("%d",&menu);
getchar();
//判断用户输入的功能进行分支选择
switch(menu)
{
case 1:
{
//下载功能
do_download(cfd,sin);
}
break;
case 2:
{
//上传功能
do_upload(cfd,sin);
}
break;
case 3: goto END;
default:printf("您输入的选项错误,请重新输入!!!\n");
}
//输入任意键结束操作
printf("请输入任意键结束!!!\n");
while(getchar() != '\n');
}
END:
return 0;
}