今日任务:tftp的文件上传下载(服务端已经准备好)
服务端(已上传)
客户端:
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <fcntl.h>
//自定义报错提示
#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以上
今日思维导图
文章来源:https://www.uudwc.com/A/b1ojg/
文章来源地址https://www.uudwc.com/A/b1ojg/