demo.c
#include <myhead.h>
int main(int argc, const char *argv[])
{
//创建用于通信的套接字文件描述符
int cfd=-1;
if((cfd=socket(AF_INET,SOCK_DGRAM,0))==-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("192.168.122.65");
char buf[516]="";
int menu;
while(1)
{
printf("\t\t=====1、上传=====\n");
printf("\t\t=====2、下载=====\n");
printf("\t\t=====3、退出=====\n");
printf("请输入功能选项:");
scanf("%d",&menu);
switch(menu)
{
/* case 1:
{
}
break;*/
case 2:
{
//发送要下载的文件名
short *p1=(short *)buf; //p1指向操作码
*p1=htons(1);
char *p2=buf+2; //p2指向文件名
strcpy(p2,"5.png");
char *p3=p2+strlen(p2)+1;//p3指向模式名
strcpy(p3,"octet");
int len=4+strlen(p2)+strlen(p3);
sendto(cfd,buf,len,0,(struct sockaddr*)&sin,sizeof(sin));
socklen_t socklen=sizeof(sin);
//fd打开目标文件
int fd=-1;
if((fd=open("/home/ubuntu/network/day3/1.png",O_WRONLY|O_TRUNC|O_CREAT,0664))==-1)
{
perror("open error");
return -1;
}
int count=1; //块编号
short *p4=p1+1;//p4指向块编号的指针
char *p5=buf+4;//p5写数据的指针
memset(buf,0,sizeof(buf));
while(1)
{
//读取数据放入buf
int res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
printf("操作码=%d,res=%d\n",ntohs(*p1),res);
if(*p1==ntohs(3))//写入
{
count=ntohs(*p4);
//printf("sizeof(p5)=%ld\n",sizeof(p5));
printf("接收块编号为%d\t",count);
if(res<516)
{
write(fd,p5,res-4);
printf("拷贝完成\n");
break;
}
//写入数据
if(write(fd,p5,512)==-1)
{
perror("write error");
return -1;
}else
{
printf("写入成功\n");
//返回ACK
memset(buf,0,sizeof(buf));
*p1=htons(4); //返回ack操作码为4
printf("返回块编号为%d\n",count);
*p4=htons(count);//返回块编号
sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
}
}else if(*p1==ntohs(5))
{
puts("");
printf("差错码为%d\n",*p2);
printf("接收数据出错\n");
return -1;
}
}
close(fd);
}
break;
case 3:
{
return 0;
}
break;
default:
printf("输入错误\n");
}
}
close(cfd);
return 0;
}
运行结果