#include <myhead.h>
//实现下载功能
int do_download(int cfd,struct sockaddr_in sin)
{
//定义变量存储下载请求包
char buf[516] = "";
//定义变量存储文件名
char fileName[40] = "";
printf("请输入文件名:");
scanf("%s",fileName);
getchar();
//组装请求包
short *p1 = (short *)buf;
*p1 = htons(1); //表明要下载
char *p2 = buf+2; //文件名段
strcpy(p2,fileName);
char *p4 = p2+strlen(p2)+1; //模式段
strcpy(p4,"octet");
int size = 4+strlen(p2) + strlen(p4);
//向服务器发送下载请求
if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin)) == -1){
perror("sendto error");
return -1;
}
printf("请求成功\n");
socklen_t socklen = sizeof(sin);
//循环接收回复服务器发来的消息
//组装数据包
//打开文件
int fd = -1;
if((fd = open(fileName,O_RDWR|O_TRUNC|O_CREAT,0666)) < 0){
perror("open error");
return -1;
}
while(1){
//接收数据包
bzero(buf,sizeof(buf));
int res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
if(res < 0){
perror("recvfrom error");
return -1;
}
//判断操作码
if(buf[1] == 3){
//写入文件
if(write(fd,buf+4,res-4) < 0){
perror("write error");
return -1;
}
//构造ACK
buf[1] = 4;
//发送ACK
if(sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin)) <0){
perror("sendto error");
return -1;
}
//判断数据包数据大小
if(res - 4<512){
printf("%s 下载完成\n",fileName);
break;
}
}else if(buf[1] == 5){
printf("%d %s\n",ntohs(*(short*)(buf+2)),buf+4);
break;
}
}
close(fd);
return 0;
}
//实现上传功能
int do_upload(int cfd,struct sockaddr_in sin)
{
//定义变量存储下载请求包
char buf[516] = "";
//定义变量存储文件名
char fileName[40] = "";
printf("请输入文件名:");
scanf("%s",fileName);
getchar();
//组装请求包
short *p1 = (short *)buf;
*p1 = htons(2); //表明要上传
char *p2 = buf+2; //文件名段
strcpy(p2,fileName);
char *p4 = p2+strlen(p2)+1; //模式段
strcpy(p4,"octet");
int size = 4+strlen(p2) + strlen(p4);
//向服务器发送上传请求
if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin)) == -1){
perror("sendto error");
return -1;
}
printf("请求成功\n");
socklen_t socklen = sizeof(sin);
//循环接收服务器发来的消息
//打开上传文件
int fd = -1;
if((fd = open(fileName,O_RDWR)) < 0){
perror("open error");
return -1;
}
int res1,res2;
int num = 0;
while(1){
//接收数据包
bzero(buf,sizeof(buf));
res1 = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
if(res1 < 0){
perror("recvfrom error");
return -1;
}
//判断接收的ACK
if(buf[1] == 4){
buf[1] = 3;
buf[3] = num;
res2 = read(fd,buf+4,512);
if(res2 < 0){
perror("read error");
return -1;
}
//向服务器发送数据包
if(sendto(cfd,buf,strlen(buf+4)+4,0,(struct sockaddr*)&sin,socklen) == -1){
perror("sendto error");
return -1;
}
num++;
if(res2 < 512){
printf("上传成功\n");
break;
}
}else if(buf[1] == 5){
printf("%d %s\n",ntohs(*(short*)(buf+2)),buf+4);
break;
}
}
close(fd);
}
int main(int argc, const char *argv[])
{
if(argc != 2){
printf("input error\n");
printf("usage:./a.out ip\n");
return -1;
}
//创建套接字
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(69);
sin.sin_addr.s_addr = inet_addr(argv[1]);
int mune = -1;
while(1){
system("clear"); //清屏
printf("\t\t=====1.下载=====\n");
printf("\t\t=====2.上传=====\n");
printf("\t\t=====0.退出=====\n");
printf("请输入功能:");
scanf("%d",&mune);
getchar();
//多分支选择
switch(mune){
case 1:{
do_download(cfd,sin);
}
break;
case 2:{
do_upload(cfd,sin);
}
break;
case 0:
goto POS;
default:printf("输入功能有误,请重新输入\n");
}
//阻塞
printf("输入任意键,按回车清空:");
while(getchar() != '\n');
}
POS:
//关闭套接字
close(cfd);
return 0;
}
11.21 tftp
最新推荐文章于 2025-05-17 15:25:47 发布