Rust 實現 NTP 客戶端 - 1

本文是用 Rust 創建簡單 NTP 客戶端系列文章的第一部分,我們將介紹協議本身,然後構建一個與 NTP 服務器通信的基本應用程序。

NTP 允許網絡中的計算機將它們的本地系統時間與 NTP 服務器上的某個時間點對齊。

我們需要設置請求的 header 來獲得服務器的 response,NTP 服務器將告訴我們時間,這個時間對於大多數應用程序來說足夠準確。

我們向 NTP Server 發送一個 48 字節長的包,第一個字節設置爲 0x1b,response 是相同的包結構,我們可以從偏移量 40 的位置讀取一個 32 位的字來獲得傳輸時間。

讓我們創建一個新的項目:

cargo new ntp_part1

編輯 Cargol.toml 文件添加 byteorder 依賴:

[dependencies]
byteorder = "1"

在 main.rs 中引入相關模塊:

use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Cursor, Seek, SeekFrom};
use std::net::UdpSocket;

然後在 main 函數中,我們寫入基本的客戶端代碼:

fn main() {
    let socket = UdpSocket::bind("0.0.0.0:0").unwrap();

    let mut transmit: Vec<u8> = vec![0; 48];
    transmit[0] = 0x1b;
    let _bytes_transmitted = socket.send_to(&transmit, "pool.ntp.org:123").unwrap();

    let mut buf = [0; 48];
    let _bytes_received = socket.recv(&mut buf).unwrap();

    let ntp_time = process_ntp_packet(&buf);
    let unix_time: u64 = ntp_time - 2208988800;

    dbg!(&unix_time);
}

這個過程遵循大多數 POSIX 系統常見的傳統 UDP 套接字創建和傳輸 / 接收範式。

在第 2 行創建套接字,我們將其綁定到端口 0 以允許操作系統定義發送端口。第 6 行發送報文,第 9 行接收報文。

收到響應後,調用 process_ntp_packet 函數:

fn process_ntp_packet(buffer: &[u8]) -> u64 {
    let mut reader = Cursor::new(buffer);
    reader.seek(SeekFrom::Start(40)).unwrap();

    let transmit_timestamp_seconds = reader.read_u32::<BigEndian>().unwrap();

    u64::from(transmit_timestamp_seconds)
}

運行 cargo run:

master:ntp_part1 Justin$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `target/debug/ntp_part1`
[src/main.rs:18] &unix_time = 1657641335

在下一部分,我們將添加一些錯誤處理和單元測試。

本文翻譯自:

https://medium.com/towardsdev/rust-foo-ntp-client-part-1-6bc4c8cce720

coding 到燈火闌珊 專注於技術分享,包括 Rust、Golang、分佈式架構、雲原生等。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/YDKIDS0NVHs6pGgN9qEW_Q