基于UDP下载
#include<header.h>
#define SER_PORT 69
#define SER_IP "192.168.125.131"
#define CLI_PORT 69
#define CLI_IP "192.168.125.168"
int main(int argc, const char *argv[])
{
//1、创建用于通信的套接字文件描述符
int cfd = socket(AF_INET, SOCK_DGRAM, 0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
printf("cfd = %d\n", cfd);
//3、数据收发
char wbuf[128] = "";
//填充服务器的地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
char rbuf[516] = "";
char buf[516] = "";
short *p1 = (short *)buf;
//组装操作码
*p1 = htons(1);
//组装文件名
char *p2 = buf + 2;
strcpy(p2, "5.png");
//组装传输模式
char *p4 = p2+strlen(p2)+1;
strcpy(p4,"octet");
//strcpy本身就存在0,可以不需要再添加
int size = 2 + strlen(p2) + strlen(p4) + 2;
//将协议包发送给服务器
sendto(cfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin));
socklen_t addrlen = sizeof(sin);
unsigned short block_num = 1;
ssize_t res = 0;
while(1)
{
//接受服务器发来的消息
res = recvfrom(cfd, rbuf, sizeof(rbuf), 0, (struct sockaddr*)&sin, &addrlen);
//网络字节序转成主机字节序
if(rbuf[1] == 3){
if( *(unsigned short*)(rbuf+2) == htons(block_num) )
//块编号
block_num++;
//写入文件
int fd = open("5.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
write(fd, rbuf+4, sizeof(rbuf+4) );
char ack;
short *p2 = (short*)ack;
*p2 = htons(4);
unsigned short *p3 = ack + 2;
p3 = htons(block_num);
//发送ACK
sendto(cfd, ack, 4, 0, (struct sockaddr*)&sin, sizeof(sin));
// 返回成功读取的字节个数,减去4字节的操作码和块编号,为数据包大小
if(res-4 < 512)
{
printf("%s 文件下载完毕\n");
break;
}
}
}
//4、关闭套接字
close(cfd);
return 0;
}