今日任务:tftp的文件上传下载(服务端已经准备好)
服务端(已上传)
客户端:
代码:
- #include
- #include
- #include
- #include
/* See NOTES */ - #include
- #include
- #include
- #include
- #include
-
- //自定义报错提示
- #define ERR_MSG(msg) do{\
- fprintf(stderr,"__%d__",__LINE__);\
- perror(msg);\
- }while(0)
-
- //#define SER_PORT 69
- //#define SER_IP "192.168.125.74"
- #define SER_PORT 69
- #define SER_IP "192.168.125.225"
- int do_upload(int cfd,struct sockaddr_in addr);
- int do_download(int cfd,struct sockaddr_in addr);
- int main(int argc, const char *argv[])
- {
- //1.创建socket套接字
- int cfd=socket(AF_INET,SOCK_DGRAM,0);
- if(cfd<0){
- ERR_MSG("socket");
- return -1;
- }
- puts("socket success");
-
-
- //3.接受和发送消息
- //目标地址信息
- struct sockaddr_in addr;
- addr.sin_family=AF_INET;
- addr.sin_port=htons(SER_PORT);
- addr.sin_addr.s_addr=inet_addr(SER_IP);
- socklen_t addrlen=sizeof(addr);
-
- //记录接受信息的目标地址信息
- struct sockaddr_in recv_addr;
- socklen_t recv_addrlen=sizeof(recv_addr);
-
- while(1){
- puts("---------------------------------");
- puts("------------1.上传---------------");
- puts("------------2.下载---------------");
- puts("------------3.退出---------------");
- puts("---------------------------------");
- puts("请选择>>");
- char choice;
- choice=getchar();
- while(getchar()!='\n');//循环吸收垃圾字符
- switch(choice){
- case '1':
- do_upload(cfd,addr);
- break;
- case '2':
- puts("download");
- do_download(cfd,addr);
- break;
- case '3':
- goto END;
- }
- }
- END:
-
- /*
- char buf[128];
- while(1){
- printf("请输入>>>");
- fgets(buf,sizeof(buf),stdin);
- buf[strlen(buf)-1]='\0';
- int send_res=sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&addr,addrlen);
- if(send_res<0){
- ERR_MSG("sendto");
- return -1;
- }
- puts("sendto success");
- if(strcmp(buf,"quit")==0)
- break;
- bzero(buf,sizeof(buf));
- int recv_res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&recv_addr,&recv_addrlen);
- if(recv_res<0){
- ERR_MSG("recvfrom");
- return -1;
- }
- puts("recvfrom success");
- printf("[%s:%d]:%s\n",inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port),buf);
- }
- */
- //4.关闭
- close(cfd);
- return 0;
- }
- int do_upload(int cfd,struct sockaddr_in addr){
- printf("请输入要上传的文件名.>>>");
- char name[20]="";
- scanf("%s",name);
- while(getchar()!=10);
-
- //组下载协议
- char buf[516]="";
- //操作码
- unsigned short *p1=(unsigned short*)buf;
- *p1=htons(2);
- //文件名
- char *p2=buf+2;
- strcpy(p2,name);
- //0
- //模式
- char *p4=p2+strlen(name)+1;
- strcpy(p4,"octet");
- //0
- int size=2+strlen(name)+1+strlen(p4)+1;
- //printf("buf==%s;size==%d",buf,size);
- //发送协议给服务器
- if(sendto(cfd,buf,size,0,(struct sockaddr*)&addr,sizeof(addr))<0){
- ERR_MSG("sendto");
- return -1;
- }
- puts("send upload protocal success");
- //打开一个文件,输入
- int fd=open(name,O_RDONLY);
- if(open<0){
- ERR_MSG("open");
- return -1;
- }
- unsigned short bNum=1;
- //重新定义一个地址的结构体,接受服务端传来的临时地址
- struct sockaddr_in dest_addr;
- socklen_t addrlen=sizeof(dest_addr);
- if(recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,&addrlen)<0){
- ERR_MSG("recvfrom");
- return -1;
- }
-
- while(1){
- //组包:操作码+块编号+数据
- bzero(buf,sizeof(buf));
- unsigned short *opNum=(unsigned short*)buf;
- *opNum=htons(3);
- unsigned short *blockNum=opNum+1;
- *blockNum=htons(bNum);
- char* msg=buf+4;
- int read_res=read(fd,msg,512);
- if(read<0){
- ERR_MSG("read");
- }
- //发包
- ssize_t sendto_res=sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,addrlen);
- if(sendto_res<0){
- ERR_MSG("sendto");
- return -1;
- }
- printf("sendto_res=%ld\n----",sendto_res);
-
- //接受ack
- if(recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,&addrlen)<0){
- ERR_MSG("recvfrom");
- return -1;
- }
-
- opNum=(unsigned short*)buf;
- blockNum=opNum+1;
- if(ntohs(*opNum)==5){
- puts("操作码错误");
- printf("%d %d:%s",ntohs(*opNum),ntohs(*blockNum),msg);
- }else if(ntohs(*opNum)==4){
- if(ntohs(*blockNum)==bNum){
- puts("ACK correct");
- }else{
- puts("ACK incorrect");
- return -1;
- }
- }
- bNum++;
-
- if(read_res<512){
- printf("bNUm==%d\n",bNum);
- puts("upload done");
- break;
- }
-
- }
- close(fd);
-
- }
- int do_download(int cfd,struct sockaddr_in addr){
- printf("请输入要下载的文件名.>>>");
- char name[20]="";
- scanf("%s",name);
- while(getchar()!=10);
-
- //组下载协议
- char buf[516]="";
- //操作码
- unsigned short *p1=(unsigned short*)buf;
- *p1=htons(1);
- //文件名
- char *p2=buf+2;
- strcpy(p2,name);
- //0
- //模式
- char *p4=p2+strlen(name)+1;
- strcpy(p4,"octet");
- //0
- int size=2+strlen(name)+1+strlen(p4)+1;
- //printf("buf==%s;size==%d",buf,size);
- //发送协议给服务器
- if(sendto(cfd,buf,size,0,(struct sockaddr*)&addr,sizeof(addr))<0){
- ERR_MSG("sendto");
- return -1;
- }
- puts("send download protocal success");
- //新建打开一个文件,等下写入
- int fd=open(name,O_WRONLY|O_CREAT|O_TRUNC,0664);
- if(fd<0){
- ERR_MSG("open");
- return -1;
- }
- //重新定义一个地址的结构体,接受服务端传来的临时地址
- struct sockaddr_in dest_addr;
- socklen_t addrlen=sizeof(dest_addr);
- while(1){
- //接受数据包
- int recv_res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,&addrlen);
- if(recv_res<0){
- ERR_MSG("recvfrom");
- return -1;
- }
- unsigned short* opNum=(unsigned short*)buf;
- unsigned short* blockNum=opNum+1;
- char * msg=(char *)(blockNum+1);
- if(ntohs(*opNum)==5){
- puts("操作码错误");
- printf("%d %d:%s",ntohs(*opNum),ntohs(*blockNum),msg);
- }else if(ntohs(*opNum)==3){
- int wr_res=write(fd,msg,recv_res-4);
- if(wr_res<0){
- ERR_MSG("write");
- }else if(wr_res<512){
- puts("recvfrom done");
- break;
- }
- }
-
- //组ACK包,吾把buf当做ack来使
- *opNum=htons(4);
-
- //回复ACK包
- sendto(cfd,buf,4,0,(struct sockaddr*)&dest_addr,addrlen);
- bzero(buf,sizeof(buf));
- }
-
-
- //
- }
运行结果:

不知道是网络的问题还是代码的问题,上传很慢,代码很快正常运行结束了,但是tftp服务端下载到win上很慢,7kb的也要5s以上
今日思维导图
