创作本文目的:记录自己的学习历程
一、TFTP协议客户端下载服务器文件
1.代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdlib.h>
//打印错误信息的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__);\
perror(msg);\
}while(0)
int main(int argc, const char *argv[])
{
//外部传参
if(argc < 3)
{
fprintf(stderr,"请输入要连接的IP PORT\n");
return -1;
}
//创建报式套接字
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("create socket success\n");
//绑定客户端的地址信息结构体(非必须绑定)
//填充要连接的服务器的地址信息结构体
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
addr.sin_addr.s_addr = inet_addr(argv[1]);
unsigned short count = 1; //记录数据包编号
ssize_t res=0; //接收函数返回值
char ack[4]=""; //ACK
char data_buf[516]=""; //数据包
char buf[128]=""; //读写请求
char filename[128]=""; //文件名
char type[]="octet"; //模式
char *tmp=NULL; //临时接收地址
unsigned short *oper=NULL; //接收操作码
unsigned short oper_host; //主机字节序的操作码
unsigned short *bnum=NULL; //接收块编号或差错码
unsigned short bnum_host; //主机字节序的块编号或差错码
//1.发送下载请求
oper=(short *)buf;
*oper = htons(1);
printf("请输入文件名:");
fgets(filename,sizeof(filename),stdin);
filename[strlen(filename)-1]=0;
tmp = buf+2;
strcpy(tmp,filename);
tmp = buf+strlen(filename)+3;
strcpy(tmp,type);
res=sendto(sfd,(void *)buf,4+strlen(filename)+strlen(type),0,(struct sockaddr *)&addr,sizeof(addr));
if(res<0)
{
ERR_MSG("send_request");
return -1;
}
printf("发送下载请求成功\n");
//创建本机接收文件
int fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);
//接受服务器给的地址信息结构体
struct sockaddr_in sin;
socklen_t addrlen=sizeof(sin);
while(1)
{
//2.接收服务器数据包
bzero(data_buf,sizeof(data_buf));
res=recvfrom(sfd,(void *)data_buf,sizeof(data_buf),0,(struct sockaddr *)&sin,&addrlen);
if(res<0)
{
ERR_MSG("recv");
return -1;
}
else if(0==res)
{
printf("server is off-line\n");
break;
}
oper_host = ntohs(*(unsigned short *)data_buf);
if(oper_host!=3)
{
printf("数据包操作码不正确:%d\n",oper_host);
bnum_host = ntohs(*((unsigned short *)data_buf+1));
printf("差错码:%d 差错信息:%s\n",bnum_host,data_buf+4);
continue;
}
bnum_host = ntohs(*((unsigned short *)data_buf+1));
if(bnum_host!=count)
{
printf("数据包块编号不正确:%d\n",bnum_host);
continue;
}
tmp=data_buf+4;
if(res<512)
{
printf("数据传输结束\n");
break;
}
res=write(fd,(void *)tmp,res-4);
//3.发送ACK应答
oper=(unsigned short *)ack;
*oper=htons(4);
bnum=oper+1;
*bnum=htons(count);
//printf("%p\t%d\n%p\t%d\n",oper,*oper,bnum,*bnum);
res=sendto(sfd,(void *)ack,sizeof(ack),0,(struct sockaddr *)&sin,addrlen);
if(res<0)
{
ERR_MSG("send_ack");
return -1;
}
//printf("发送ACK成功\n");
count++;
}
//关闭套接字
close(sfd);
//关闭下载的文件
close(fd);
return 0;
}
2.运行效果
二、TFTP协议客户端上传本地文件
1.代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdlib.h>
//打印错误信息的宏函数
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__);\
perror(msg);\
}while(0)
int main(int argc, const char *argv[])
{
//外部传参
if(argc < 3)
{
fprintf(stderr,"请输入要连接的IP PORT\n");
return -1;
}
//创建报式套接字
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("create socket success\n");
//绑定客户端的地址信息结构体(非必须绑定)
//填充要连接的服务器的地址信息结构体
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
addr.sin_addr.s_addr = inet_addr(argv[1]);
unsigned short count = 0; //记录数据包编号
ssize_t res=0; //接收函数返回值
char ack[128]=""; //ACK
char data_buf[516]=""; //数据包
char buf[128]=""; //读写请求
char filename[128]=""; //文件名
char type[]="octet"; //模式
char *tmp=NULL; //临时接收地址
unsigned short *oper=NULL; //接收操作码
unsigned short oper_host; //主机字节序的操作码
unsigned short *bnum=NULL; //接收块编号或差错码
unsigned short bnum_host; //主机字节序的块编号或差错码
//1.发送上传请求
/*
oper=(short *)buf;
*oper = htons(2);
tmp = buf+2;
strcpy(tmp,filename);
tmp = buf+strlen(filename)+3;
strcpy(tmp,type);
*/
printf("请输入文件名:");
fgets(filename,sizeof(filename),stdin);
filename[strlen(filename)-1]=0;
res = sprintf(buf,"%c%c%s%c%s%c",0,2,filename,0,type,0);
if(sendto(sfd,buf,res,0,(struct sockaddr *)&addr,sizeof(addr))<0)
{
ERR_MSG("send_request");
return -1;
}
printf("发送下载请求成功\n");
//打开本机上传文件
int fd = open(filename,O_RDONLY);
//接受服务器给的地址信息结构体
struct sockaddr_in sin;
socklen_t addrlen=sizeof(sin);
while(1)
{
//2.接收服务器的ACK应答
res=recvfrom(sfd,(void *)ack,sizeof(ack),0,(struct sockaddr *)&sin,&addrlen);
if(res<0)
{
ERR_MSG("send_ack");
return -1;
}
//printf("接收服务器ACK成功\n");
oper_host = ntohs(*(unsigned short *)ack);
if(oper_host!=4)
{
printf("操作码不正确:%d\n",oper_host);
bnum_host = ntohs(*((unsigned short *)ack+1));
printf("差错码:%d 差错信息:%s\n",bnum_host,ack+4);
continue;
}
bnum_host = ntohs(*((unsigned short *)ack+1));
if(bnum_host!=count)
{
printf("数据包块编号不正确:%d\n",bnum_host);
continue;
}
count++;
//3.给服务器发送数据包
bzero(data_buf,sizeof(data_buf));
oper=(unsigned short *)data_buf;
*oper=htons(3);
bnum=oper+1;
*bnum=htons(count);
//printf("%p\t%d\n%p\t%d\n",oper,*oper,bnum,*bnum);
tmp=data_buf+4;
res=read(fd,tmp,512);
if(res<0)
{
ERR_MSG("read");
return -1;
}
res=sendto(sfd,(void *)data_buf,res+4,0,(struct sockaddr *)&sin,sizeof(sin));
if(res<0)
{
ERR_MSG("recv");
return -1;
}
else if(0==res)
{
printf("server is off-line\n");
break;
}
if(res<512)
{
printf("数据传输结束\n");
break;
}
//printf("给服务器发送数据包成功:%ld\n",res);
}
//关闭套接字
close(sfd);
//关闭上传的文件
close(fd);
return 0;
}