作业
1.文件的下载与上传
2.思维导图
1.
代码1.
#include<myhead.h>
int do_download(int sdf,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);
int set=0;
//向服务端提供下载请求
if((set=sendto(sdf,buf,size,0,(struct sockaddr*)&sin,sizeof(sin)))==-1)
{
perror("sendto error");
}
// 读取的字节个数
printf("set=%d\n",set);
//循环接受回复服务器的信息
int fd=-1; //创建一个文件
socklen_t len=sizeof(sin);
short num=0; //记录本地块编号
int res=0;
int wr;
int sed;
char bbuf[516]="";
while(1)
{
bzero(buf,sizeof(buf));
//读取的字节个数
res=recvfrom(sdf,buf,sizeof(buf),0,(struct sockaddr*)&sin,&len);
if(res<0)
{
perror("recvfrom error");
}
system("ls");
printf("res=%d\n",res);
printf("buf[0]=%d\n",buf[0]);
if(3==buf[1])//数据包
{
if(*(short*)(buf+2)==htons((num+1))) //服务器返回的数据包的块编号和本地记录的块编号是否一致
{
num++;//更新本地块编号
printf("num=%d\n",num);
//创建并打开文件
if((fd=open(filename,O_CREAT|O_WRONLY|O_APPEND,0664))<0)//创建文件
{
perror("open error");
}
printf("write.res=%d\n",res);
//将数据包的操作码和快编号去掉写入文件
if( (wr=write(fd,buf+4,res-4))<0)
{
perror("write error");
}
printf("wr=%d\n",wr);
buf[1]=4;//操作码切换为ACK
//将操作码和块编号回传给服务器
if((sendto(sdf,buf,4,0,(struct sockaddr*)&sin,len))<0)
{
perror("sendto error");
}
if(res-4<512)
{
printf("%s传输完成\n",filename);
break;
}
}
}
else if(5==buf[1])//错误
{
printf("传输失败\n");
close(fd);
return -1;
}
}
close(fd);
return 0;
}
int do_uoload(int sdf,struct sockaddr_in sin)
{
printf("请输入要上传的文件>>:");
char buf[516]="";
char name[40]="";
scanf("%s",name);
getchar();
int fd = -1;
if((fd=open(name,O_RDONLY))<0)
{
perror("open error");
}
short *p1=(short *)buf;
*p1=htons(2);
char *p2=buf+2;
strcpy(p2,name);
char *p4=p2+strlen(p2)+1;
strcpy(p4,"octet");
int len=4+strlen(p2)+strlen(p4);
int sen=-1;
//向服务器发送上传请求
if((sen=sendto(sdf,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin)))<0)
{
perror("sendto error");
}
printf("sen=%d\n",sen);
//服务器回传的字节个数
int res;
//本地块编号
short num=0;
socklen_t socklen=sizeof(sin);
while(1)
{
bzero(buf,sizeof(buf));
//循环接收服务器信息
res=recvfrom(sdf,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
if(res<0)
{
perror("recvfrom error");
}
printf("res=%d\n",res);
printf("buf[1]=%d\n",buf[1]);
//服务器返回的应答包是4
if(4==buf[1]) //数据包
{
//当前数据包的编号是否等于服务起上的块编号
//防止丢包
if(num== ntohs(*(short*)(buf+2)))
{
buf[1]=3;
//填充块编号
num++;
*(short*)(buf+2)=htons(num);
//读取数据
res=read(fd,buf+4,sizeof(buf)-4);
if(0==res)
{
printf("上传完毕\n");
break;
}else if(res<0)
{
perror("read error");
}
//接受服务器数据
//读取字节数res+操作码2字节+块编号
if(sendto(sdf,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("sendto error");
}
}else{
printf("网络问题\n");
break;
}
}
else if(5==buf[1])
{
printf("错误\n");
break;
}
}
close(fd);
return 0;
}
int main(int argc, const char *argv[])
{
if(argc!=-2)
{
printf("input error\n");
printf("usage ip ./a.out ip\n");
}
int sdf;
sdf=socket(AF_INET,SOCK_DGRAM,0);
if(sdf==-1)
{
perror("socket error");
}
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(69);
sin.sin_addr.s_addr=inet_addr(argv[1]);
int nume=-1;
while(1)
{
system("clear");
printf("\n==================\n");
printf("\n请选择需要的功能\n");
printf("\n1.下载\n");
printf("\n2.上传\n");
printf("\n3.退出\n");
printf("\n==================\n");
scanf("%d",&nume);
getchar();
switch(nume)
{
case 1: {do_download(sdf,sin); } break;
case 2: {do_uoload(sdf,sin);} break;
case 3: goto POS; break;
default: printf("请重新输入\n");
}
printf("请输入任意,按回车键清空\n");
while(getchar()!='\n');
}
POS:
close(sdf);
return 0;
}
1.
成果图
下载
上传
思维导图