#include #include #include #include #include #include #include #include #include /* ./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; }