实现tpfp服务器下载部分
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ERR_MSG(msg) do{\
printf("line=%d\n",__LINE__);\
perror(msg);\
}while(0)
#define PORT 69
#define IP "192.168.9.66"
#define PACKET_SIZE 516
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("socket creat success line = %d\n",__LINE__);
//填充服务器自身的地址信息结构体
//真实的地址信息结构体根据地址族制定 man 7 IP
struct sockaddr_in sin;
sin.sin_family=AF_INET;//必须填充AF_INET
sin.sin_port=htons(PORT);//端口号的网络字节序 1024 ~ 49151
sin.sin_addr.s_addr=inet_addr(IP);// 填充本机IP
//组下载协议
char buf[516]="";
int n;
short int* ptr=(short int *)buf;
*ptr=htons(1);
char *ptr2=buf+2;
//strcpy(ptr2,"1_armcli.c");
strcpy(ptr2,"6.png"); //定义要打开的文件
char *ptr3 = ptr2+strlen(ptr2)+1;
strcpy(ptr3,"octet");
int size=2+strlen(ptr2)+1+strlen(ptr3)+1;
if(sendto(sfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin))<0) //向服务器发送下载协议
{
ERR_MSG("sendto");
return -1;
}
struct sockaddr_in fake_sin; //定义一个地址结构体变量来接受服务器的IP和临时端口信息
int len=sizeof(fake_sin);
int fd_w=open("./copy.png",O_WRONLY|O_CREAT|O_TRUNC,0664); //将要写入的文件打开
if(fd_w<0)
{
printf("error __%d__\n",__LINE__);
return -1;
}
short int i=0;
int flag=0;
while (1)
{
bzero(buf,sizeof(buf)); //每次循环前将数组清零
//判断每次收到的字节数是否等于516,如果小于516则说明是最后一个数据包,将flag置1
//最后写入一次然后退出循环
if((n=recvfrom(sfd,buf,PACKET_SIZE,0,(struct sockaddr*)&fake_sin,&len))<PACKET_SIZE)
flag = 1;
char* ptr4=buf+4;//buf数组前四个字节不属于要写入的数据,直接跳过
int len_buf=n-4; //写入的真实长度
if(write(fd_w,ptr4,len_buf)<0)
{
ERR_MSG("write");
return -1;
}
printf("写入ing\n");
short int ack[2]; //定义一个数组来存储应答信号
short int* ptr5 = (short int*)buf; //用同为两个字节short类型去获取操作码
i = ntohs(*ptr5); //将获取到的操作码由网络字节序转为本机字节序
i++; //操作码自加1
*ptr5 = htons(i); //将自加后的操作码再次转为网络字节序存储到ptr5中
short int* ptr6 = ptr5 + 1; //用ptr6获取buf中存储的块编号
ack[0] = *ptr5;
ack[1] = *ptr6; //拼接应答信号
if (sendto(sfd, ack, sizeof(ack), 0, (struct sockaddr*)&fake_sin, sizeof(fake_sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
printf("应答\n");
// 如果接收到的数据小于512字节,并且本次接收已经不是完整的512字节,
// 则为最后一包数据,直接退出循环
if (flag == 1 && len_buf < PACKET_SIZE - 4)
break;
}
return 0;
}