网络编程-day2 0517

实现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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值