1、下载
#include <myhead.h>
#define SER_PORT 69 //指定要将数据发给谁,填谁的端口号
#define SER_IP "192.168.101.50" //指定要将数据发给谁,填谁的IP
int do_download(int cfd,struct sockaddr_in sin);
int main(int argc, const char *argv[])
{
//创建报式套接字 socket
int cfd = socket(AF_INET, SOCK_DGRAM, 0);
if(cfd < 0)
{
ERR_MSG("socket");
return -1;
}
printf("socket create success cfd=%d\n", cfd);
//填充服务器的地址信息结构体,给sendto函数使用
//真实的地址信息结构体根据地址族指定,AF_INET:man 7 IP
struct sockaddr_in sin;
sin.sin_family = AF_INET; //必须填AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
char choose=0;
while(1)
{
system("clear");
printf("------------------------\n");
printf("---------1、下载--------\n");
printf("---------2、上传--------\n");
printf("---------3、退出--------\n");
printf("------------------------\n");
printf("请输入:");
scanf("%c",&choose);
while(getchar()!=10); //循环吸收垃圾字符,直到吸收到\n字符
switch(choose)
{
case '1':
do_download(cfd,sin);
break;
case '2':
//do_upload();
break;
case '3':
goto END;
break;
default:
printf("输入错误,请重新输入\n");
break;
}
printf("输入任意字符清屏:");
while(getchar()!=10);
}
#if 0
char buf[128] = ""; /*{{{*/
struct sockaddr_in rcvaddr; //存储发送方的地址信息;
socklen_t addrlen = sizeof(rcvaddr);
while(1)
{
bzero(buf, sizeof(buf));
//发送数据----->从终端获取数据发送给指定端
printf("请输入>>> ");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if(sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
printf("sendto success\n");
//接收数据
/*
//在不考虑sendto回复信息的情况下可以使用
//if(recvfrom(cfd, buf, sizeof(buf), 0, NULL, NULL) < 0)
//if(recv(cfd, buf, sizeof(buf), 0) < 0)
//if(read(cfd, buf, sizeof(buf)) < 0)
*/
bzero(buf, sizeof(buf));
if(recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr*)&rcvaddr, &addrlen) < 0)
{
ERR_MSG("recv");
return -1;
}
printf("[%s:%d] : %s\n", inet_ntoa(rcvaddr.sin_addr), ntohs(rcvaddr.sin_port), buf);
}/*}}}*/
#endif
END:
//关闭套接字
close(cfd);
return 0;
}
int do_download(int cfd, struct sockaddr_in sin)
{
char filename[20] = "";
char buf[516] = "";
bzero(buf, sizeof(buf));
printf("请输入要下载的文件名:");
fgets(filename, sizeof(filename), stdin);
filename[strlen(filename) - 1] = 0;
//发送下载请求包
int size = sprintf(buf, "%c%c%s%c%s%c", 0, 1, filename, 0, "octet", 0);
if (sendto(cfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("sendto");
return -1;
}
int fd = -1, flag = 0;
socklen_t addrlen = sizeof(sin);
ssize_t res = 0;
unsigned short num = 0; //记录数据包的编号
//循环接收数据包,回复ACK
while (1)
{
bzero(buf, sizeof(buf));
res = recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &addrlen);
if (res < 0)
{
perror("recvfrom");
return -1;
}
if (3 == buf[1])
{
//判断收到的包是否出错
if (htons(num + 1) == *(unsigned short *)(buf + 2))
{
num++;
if (0 == flag)
{
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (fd < 0)
{
perror("open");
return -1;
}
flag = 1;
}
if (write(fd, buf + 4, res - 4) < 0)
{
perror("write");
return -1;
}
//回复ACK,
buf[1] = 4;
if (sendto(cfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("sendto");
return -1;
}
//判断数据包中下载的数据是否小于512,小于512默认传输完成
if (res - 4 < 512)
{
printf("%s 文件下载完毕\n", filename);
break;
}
}
}
else if (5 == buf[1])
{
fprintf(stderr, "错误码:%d 错误信息:%s\n", ntohs(*(unsigned short *)(buf + 2)), buf + 4);
break;
}
}
close(fd);
return 0;
}
2、思维导图