1、基于UDP的TFTP文件传输
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<string.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"%d",__LINE__);\
perror("msg");\
}while(0)
#define SER_IP "192.168.2.131"
#define SER_PORT 69
#define CLI_IP "192.168.0.111"
#define CLI_PORT 7777
void Download();
void Upload();
int main(int argc, const char *argv[])
{
int option =-1;
while(1)
{
printf("************************\n");
printf("********1、下载*********\n");
printf("********2、上传*********\n");
printf("********3、退出*********\n");
printf("************************\n");
printf("************************\n");
scanf("%d",&option);
while(getchar() != 10);
if(1 == option)
Download();
else if(2 == option)
Upload();
else if(3 == option)
break;
}
//关闭
return 0;
}
void Download()
{
//创建报式套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd < 0)
{
ERR_MSG("socket");
return;
}
char buf[516]={0};
//创建填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
socklen_t addrlen = sizeof(sin);
//设置读请求
*(short*)buf = htons(1);
//printf("%hd\t__%d__\n",ntohs(*(short*)buf),__LINE__);
//将文件名写入到buf中
printf("请输入要下载的文件名>>>>>>\n");
scanf("%s",buf+2);
while(getchar() != 10);
char pathname[128]="";
strcpy(pathname,buf+2);
strcpy(buf+2+strlen(buf+2)+1,"octet");
//printf("%hd %s %s\n",ntohs(*(short*)buf),buf+2,buf+2+strlen(buf+2)+1);
char *p1 = buf+2+strlen(buf+2)+1;
int size = 4 + strlen(buf+2)+strlen(p1)+1;
//发送数据
if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return;
}
printf("发送成功 size=%d\n",size);
ssize_t res = 0,num = -1;
short count=1;
int fd = -1;;
while(1)
{
//接收数据
bzero(buf,sizeof(buf));
res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
if(res < 0)
{
ERR_MSG("recvfrom");
return;
}
// printf("[%s:%d]: %s\n",inet_ntoa(rcvaddr.sin_addr),ntohs(rcvaddr.sin_port),buf);
// printf("%d : %d\t%s\n",ntohs(*(short*)buf),ntohs(*(short*)(buf+2)),buf+4);
if(ntohs(*(short*)buf) == 3)
{
if(1 == ntohs(*(short*)(buf+2)))
{
//创建文件
fd = open(pathname,O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd < 0)
{
ERR_MSG("open");
return;
}
}
if(ntohs(*(short*)(buf+2)) == count)
{
num = write(fd,buf+4,res-4);
if(num < 0)
{
ERR_MSG("read");
break;
}
else if(num < 512)
{
printf("Download sucess\n");
break;
}
//发送数据
bzero(buf,sizeof(buf));
*(short *)buf = htons(4);
*((short *)(buf+2))=htons(count++);
if(sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return ;
}
}
}
else if(ntohs(*(short *)buf) == 5)
{
printf("%s __%d__\n",buf+4,__LINE__);
break;
}
// printf("发送成功\n");
}
close(fd);
close(cfd);
}
void Upload()
{
//创建报式套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd < 0)
{
ERR_MSG("socket");
return;
}
char buf[516]={0};
//创建填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
socklen_t addrlen = sizeof(sin);
//设置写请求
*(short*)buf = htons(2);
//printf("%hd\t__%d__\n",ntohs(*(short*)buf),__LINE__);
//将文件名写入到buf中
printf("请输入要上传的文件名>>>>>>\n");
scanf("%s",buf+2);
while(getchar() != 10);
char pathname[128]="";
strcpy(pathname,buf+2);
strcpy(buf+2+strlen(buf+2)+1,"octet");
// printf("%hd %s %s\n",ntohs(*(short*)buf),buf+2,buf+2+strlen(buf+2)+1);
char *p1 = buf+2+strlen(buf+2)+1;
int size = 4 + strlen(buf+2)+strlen(p1)+1;
//发送数据
if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return;
}
printf("发送成功 size=%d\n",size);
ssize_t res = 0,num = -1;
short count=0;
int flag = 1;
int fd = -1;;
while(1)
{
//接收数据
bzero(buf,sizeof(buf));
res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
if(res < 0)
{
ERR_MSG("recvfrom");
return;
}
// printf("*****%d*****%d*****\n",ntohs(*(short*)buf),ntohs(*(short*)(buf+2)));
if(ntohs(*(short *)buf) == 5)
{
printf("*******************%d __%d__\n",ntohs(*(short*)(buf+2)),__LINE__);
break;
}
// printf("[%s:%d]: %s\n",inet_ntoa(rcvaddr.sin_addr),ntohs(rcvaddr.sin_port),buf);
else if(ntohs(*(short*)buf) == 4)
{
if(flag == 1)
{
//创建文件
fd = open(pathname,O_RDONLY);
if(fd < 0)
{
ERR_MSG("open");
return;
}
flag = 0;
}
if(ntohs(*(short*)(buf+2)) != count)
{
lseek(fd,512*(ntohs(*(short*)(buf+2))),SEEK_SET);
count = ntohs(*(short*)(buf+2));
}
if(ntohs(*(short*)(buf+2)) == count)
{
// printf("%s",buf+4);
bzero(buf,sizeof(buf));
//发送数据
*(short *)buf = htons(3);
*((short *)(buf+2))=htons(++count);
res = read(fd,buf+4,512);
if(res < 0)
{
ERR_MSG("read");
break;
}
///
if(count ==5)
count++; //手动产生错误包,修改文件偏移量后读取数据并发送
///
// printf("%d : %d\t%s\n",ntohs(*(short*)buf),ntohs(*(short*)(buf+2)),buf+4);
if(res == 0)
{
printf("Update sucess\n");
break;
}
if(sendto(cfd,buf,res+4,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return ;
}
}
}
// printf("发送成功\n");
}
close(fd);
close(cfd);
}
ubuntu@ubuntu:TFTP$ gcc 02_udpCli_TFTP.c
ubuntu@ubuntu:TFTP$ ./a.out
************************
********1、下载*********
********2、上传*********
********3、退出*********
************************
1
请输入要下载的文件名>>>>>>
5.png
1 5.png octet
发送成功 size=15
Download sucess
************************
********1、下载*********
********2、上传*********
********3、退出*********
************************
^C
ubuntu@ubuntu:TFTP$ ls
02_udpCli_TFTP.c 2 5 a.out asd.c d huahua.c
1.png 2octet 5.png asd asdoctet dict.txt
ubuntu@ubuntu:TFTP$ eog 5.png
ubuntu@ubuntu:TFTP$