tftp
协议概述
简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用
UDP
传输
特点:
是应用层协议
基于
UDP
协议实现
数据传输模式
octet
:二进制模式(常用)
mail
:已经不再支持
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
//打印错误新的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr, " __%d__ ", __LINE__);\
perror(msg);\
}while(0)
int main(int argc, const char *argv[])
{
umask(0);
if(argc < 3)
{
fprintf(stderr, "请输入IP port\n");
return -1;
}
//将获取到的端口号字符串,转换成整形
/* int port = atoi(argv[2]);
if(port < 1024 || port > 49151)
{
fprintf(stderr, "port %d input error!! 1024~49151\n", port);
return -1;
}*/
unsigned short code =0; //操作码
unsigned short num =0; //块编号
char txt[666]={0}; //文件内容
int block_num=0; //用来校验接收到的包
int fd=0; //打开文件
int res=0; //接收recvfrom返回的字节数
//创建报式套接字
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
//填充服务器的IP地址以及端口号 -->因为客户端要主动发送数据包给服务器
struct sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_family = AF_INET;
//端口号 69
sin.sin_port = htons(atoi(argv[2]));
//ip地址填写服务器(WINDOWS)的ip地址
sin.sin_addr.s_addr = inet_addr(argv[1]);
// struct sockaddr_in rcv_addrmsg; //存储接收到的数据包来自哪里
socklen_t addrlen = sizeof(sin);
char filename[64]={0};
printf("请输入文件名:>>");
scanf("%s",filename);
fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0777);
char buff[666]={0};
//组装包
int numb = sprintf(buff,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);
//发送请求
if(sendto(sfd, buff, numb, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
while(1)
{
res=recvfrom(sfd, buff, 666, 0, (struct sockaddr*)&sin,&addrlen);
printf("%d",res);
//解析数据包
code =ntohs(*(unsigned short*)buff); //操作码
if(code == 3)
{
num =ntohs(*(unsigned short*)(buff+2));//块编号
//strncpy(txt,buff+4,512); //接收文件,每次512字节
if(write(fd,buff+4,res-4)<0)
{
ERR_MSG("write");
return -1;
}//将txt内的内容写入到fd中
//ACK应答
*(unsigned short *)buff=htons(4);
*(unsigned short *)(buff+2)=htons(num);
//发送应答给服务器
if(sendto(sfd, buff, 4, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
if(res<516)
{
printf("download over\n");
break;
}
}else if(code == 5)
{
printf("%s\n",buff+4);
break;
}
}
//关闭套接字
close(fd);
close(sfd);
return 0;
}