#include #include #include #include #include #include #include #include #include /** * ./a.out server_ip 下载的文件名 * ./tftpc server_ip filename */ int main(int argc, char const *argv[]) { if (argc < 3) { printf("format: %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; } // 生成请求数据包 char request[64]; int request_size = sprintf(request, "%c%c%s%c%s%c", 0, 1, argv[2], 0, "octet", 0); // 发送请求 struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(69); 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, data_addr_len); ssize_t len = recvfrom(sock_fd, buf, 516, 0, (struct sockaddr *)&data_addr, &data_addr_len); // 验证接收的数据是否OK if (buf[1] == 3) { // 创建本地文件的描述符(打开或创建文件) int fd = open(argv[2], O_CREAT | O_WRONLY, 0666); while (1) { // 收到的是数据包 write(fd, buf + 4, len - 4); // 回ACK buf[1] = 4; 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包,包含请求选项回传的值 } close(sock_fd); return 0; }