qfedu-network-advanced-level/day3/homework/h3.c

96 lines
2.6 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/*
./a.out server_ip 下载的文件名
*/
int main(int argc, char const *argv[])
{
if (argc != 3)
{
printf("usage: %s server_ip filename\n", argv[0]);
return -1;
}
int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0)
{
perror("socket");
return -1;
}
struct stat st;
stat(argv[2], &st);
int tsize = st.st_size;
// 生成请求数据包
char request[64];
// char *tsize = 0;
int request_size = sprintf(request, "%c%c%s%c%s%c%d%c", 0, 1, argv[2], 0, "octet", 0, tsize, 0);
// 发送请求
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(69); // 服务器TFTP端口
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 服务器地址
sendto(sock_fd, request, request_size, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
char buf[516] = "";
struct sockaddr_in data_addr;
socklen_t data_addr_len = sizeof(data_addr);
bzero(&data_addr, sizeof(data_addr));
ssize_t len = recvfrom(sock_fd, buf, 516, 0, (struct sockaddr *)&data_addr, &data_addr_len);
// 验证接收的数据是否是 OK
if (buf[1] == 3)
{
// printf("收到的文件大小为 %d\n", tsize);
// 创建本地文件的描述符(打开或创建文件)
int fd = open(argv[2], O_CREAT | O_WRONLY, 0666);
while (1)
{
printf("文件名为 %s,文件大小为 %s\n", argv[2], buf + 2);
// 收到的是数据报
write(fd, buf + 4, len - 4);
// 回ACK
buf[1] = 4;
// buf[2] = "tsize";
sendto(sock_fd, buf, 4, 0, (struct sockaddr *)&data_addr, sizeof(data_addr));
if (len < 516)
{
printf("数据接收完成\n");
break;
}
bzero(&data_addr, data_addr_len);
bzero(buf, sizeof(buf));
len = recvfrom(sock_fd, buf, 516, 0, (struct sockaddr *)&data_addr, &data_addr_len);
}
close(fd);
}
else if (buf[1] == 5)
{
// 收到的是错误信息
printf("error: %s\n", buf + 4);
}
// else if (buf[1] == 6)
// {
// // 收到OACK包包含请求选项回传的值
// printf("文件名为 %s,文件大小为 %s\n", argv[2], buf + 2);
// }
close(sock_fd);
return 0;
}