Manoratra mpanjifa NTP tsotra

Salama, Habrausers. Androany aho dia te hiresaka momba ny fomba hanoratana ny mpanjifa NTP tsotra anao. Amin'ny ankapobeny, ny resaka dia hitodika amin'ny firafitry ny fonosana sy ny fomba fanodinana ny valiny avy amin'ny mpizara NTP. Ny kaody dia hosoratana amin'ny Python, satria hitako fa tsy misy fiteny tsara kokoa ho an'ny zavatra toy izany. Ny connoisseurs dia hanamarika ny fitovian'ny kaody amin'ny code ntplib - "Nahazo aingam-panahy" aho tamin'izany.

Dia inona marina ny NTP? NTP dia protocole hifaneraserana amin'ny mpizara fotoana marina. Ity protocol ity dia ampiasaina amin'ny milina maoderina maro. Ohatra, ny serivisy w32tm amin'ny windows.

Misy dikan-teny 5 amin'ny protocole NTP. Ny voalohany, ny dikan-teny 0 (1985, RFC958), dia heverina ho efa lany andro amin'izao fotoana izao. Misy dikan-teny vaovao kokoa ampiasaina amin'izao fotoana izao: dikan-teny 1 (1988, RFC1059), dikan-teny 2 (1989, RFC1119), dikan-teny 3 (1992, RFC1305), ary dikan-teny 4 (1996, RFC2030). Mifanaraka amin'ny tsirairay ny dikan-teny 1-4; ny algorithma fiasan'izy ireo ihany no tsy mampitovy azy ireo. lohamilina.

endrika fonosana

Manoratra mpanjifa NTP tsotra

Leap indicator (manondro fanitsiana) - isa manondro fampitandremana momba ny fandrindrana faharoa. Midika hoe:

  • 0 - tsy misy fanitsiana
  • 1 - ny minitra farany amin'ny andro dia misy 61 segondra
  • 2 - ny minitra farany amin'ny andro dia misy 59 segondra
  • 3 - tsy miasa ny mpizara (tsy mifanandrify ny fotoana)

Laharana kinova (laharan'ny dikan-teny) – NTP protocole version number (1-4).

lamaody (mode) — fomba fiasan'ny mpandefa fonosana. Sanda 0 ka hatramin'ny 7, matetika indrindra:

  • 3 - mpanjifa
  • 4 – mpizara
  • 5 - fomba fampitana

sosona (ambaratonga sosona) - ny isan'ny sosona manelanelana eo amin'ny mpizara sy ny famantaranandro fanondro (1 - ny mpizara dia maka data mivantana avy amin'ny famantaranandro fanondro, 2 - ny mpizara dia maka angona avy amin'ny mpizara misy sosona 1, sns.).
Pool dia integer voasonia maneho ny elanelana ambony indrindra eo amin'ny hafatra mifanesy. Ny mpanjifan'ny NTP dia mamaritra eto ny elanelam-potoana izay antenainy hanaovana fitsapan-kevitra ny mpizara, ary ny mpizara NTP dia mamaritra ny elanelam-potoana izay antenainy hodinihina. Ny sanda dia mitovy amin'ny logaritma mimari-droa segondra.
fametrahana mazava tsara (accuracy) dia isa voasonia maneho ny fahamarinan'ny famantaranandron'ny rafitra. Ny sanda dia mitovy amin'ny logaritma mimari-droa segondra.
Fanemorana ny fakany (fahatarana amin'ny serivisy) - ny fotoana ilana ny famakian'ny famantaranandro mba hahatongavana amin'ny mpizara NTP, ho isa segondra raikitra.
Fiparitahan'ny faka (fiparitahan'ny mpizara) - fiparitahan'ny famakiana famantaranandron'ny mpizara NTP ho segondra maromaro misy teboka raikitra.
Ref id (famantarana loharano) - id famantaranandro. Raha manana stratum 1 ny mpizara, dia ny ref id no anaran'ny famantaranandro atomika (karazana ASCII 4). Raha mampiasa mpizara hafa ny mpizara, dia misy ny adiresin'ity mpizara ity ny ref id.
Ny saha 4 farany dia maneho ny fotoana - 32 bit - ny ampahany integer, 32 bit - ny ampahany fractional.
Reference - ny famakiana famantaranandro farany amin'ny mpizara.
avy - fotoana nandefasana ny fonosana (fenoin'ny mpizara - bebe kokoa momba ity etsy ambany ity).
Raiso – fotoana nandraisan'ny mpizara ny fonosana.
mamindra - fotoana fandefasana ny fonosana avy amin'ny mpizara mankany amin'ny mpanjifa (fenoin'ny mpanjifa, bebe kokoa amin'ity etsy ambany ity).

Tsy handinika ireo sehatra roa farany isika.

Andao hanoratra ny fonosanay:

Kaody fonosana

class NTPPacket:
    _FORMAT = "!B B b b 11I"

    def __init__(self, version_number=2, mode=3, transmit=0):
        # Necessary of enter leap second (2 bits)
        self.leap_indicator = 0
        # Version of protocol (3 bits)
        self.version_number = version_number
        # Mode of sender (3 bits)
        self.mode = mode
        # The level of "layering" reading time (1 byte)
        self.stratum = 0
        # Interval between requests (1 byte)
        self.pool = 0
        # Precision (log2) (1 byte)
        self.precision = 0
        # Interval for the clock reach NTP server (4 bytes)
        self.root_delay = 0
        # Scatter the clock NTP-server (4 bytes)
        self.root_dispersion = 0
        # Indicator of clocks (4 bytes)
        self.ref_id = 0
        # Last update time on server (8 bytes)
        self.reference = 0
        # Time of sending packet from local machine (8 bytes)
        self.originate = 0
        # Time of receipt on server (8 bytes)
        self.receive = 0
        # Time of sending answer from server (8 bytes)
        self.transmit = transmit

Mba handefasana (sy handray) fonosana ho an'ny mpizara dia tsy maintsy afaka mamadika azy ho array byte isika.
Ho an'ity hetsika ity (ary mivadika) dia hanoratra fiasa roa isika - pack() sy unpack():

fonosana fonosana

def pack(self):
        return struct.pack(NTPPacket._FORMAT,
                (self.leap_indicator << 6) + 
                    (self.version_number << 3) + self.mode,
                self.stratum,
                self.pool,
                self.precision,
                int(self.root_delay) + get_fraction(self.root_delay, 16),
                int(self.root_dispersion) + 
                    get_fraction(self.root_dispersion, 16),
                self.ref_id,
                int(self.reference),
                get_fraction(self.reference, 32),
                int(self.originate),
                get_fraction(self.originate, 32),
                int(self.receive),
                get_fraction(self.receive, 32),
                int(self.transmit),
                get_fraction(self.transmit, 32))

unpack function

def unpack(self, data: bytes):
        unpacked_data = struct.unpack(NTPPacket._FORMAT, data)

        self.leap_indicator = unpacked_data[0] >> 6  # 2 bits
        self.version_number = unpacked_data[0] >> 3 & 0b111  # 3 bits
        self.mode = unpacked_data[0] & 0b111  # 3 bits

        self.stratum = unpacked_data[1]  # 1 byte
        self.pool = unpacked_data[2]  # 1 byte
        self.precision = unpacked_data[3]  # 1 byte

        # 2 bytes | 2 bytes
        self.root_delay = (unpacked_data[4] >> 16) +
            (unpacked_data[4] & 0xFFFF) / 2 ** 16
         # 2 bytes | 2 bytes
        self.root_dispersion = (unpacked_data[5] >> 16) +
            (unpacked_data[5] & 0xFFFF) / 2 ** 16 

        # 4 bytes
        self.ref_id = str((unpacked_data[6] >> 24) & 0xFF) + " " + 
                      str((unpacked_data[6] >> 16) & 0xFF) + " " +  
                      str((unpacked_data[6] >> 8) & 0xFF) + " " +  
                      str(unpacked_data[6] & 0xFF)

        self.reference = unpacked_data[7] + unpacked_data[8] / 2 ** 32  # 8 bytes
        self.originate = unpacked_data[9] + unpacked_data[10] / 2 ** 32  # 8 bytes
        self.receive = unpacked_data[11] + unpacked_data[12] / 2 ** 32  # 8 bytes
        self.transmit = unpacked_data[13] + unpacked_data[14] / 2 ** 32  # 8 bytes

        return self

Ho an'ny kamo, toy ny fampiharana - code izay mamadika fonosana ho kofehy tsara tarehy

def to_display(self):
        return "Leap indicator: {0.leap_indicator}n" 
                "Version number: {0.version_number}n" 
                "Mode: {0.mode}n" 
                "Stratum: {0.stratum}n" 
                "Pool: {0.pool}n" 
                "Precision: {0.precision}n" 
                "Root delay: {0.root_delay}n" 
                "Root dispersion: {0.root_dispersion}n" 
                "Ref id: {0.ref_id}n" 
                "Reference: {0.reference}n" 
                "Originate: {0.originate}n" 
                "Receive: {0.receive}n" 
                "Transmit: {0.transmit}"
                .format(self)

Mandefa fonosana amin'ny mpizara

Ny fonosana misy saha feno dia tsy maintsy alefa any amin'ny mpizara Version, lamaody и mamindra. The mamindra tsy maintsy mamaritra ny fotoana amin'izao fotoana izao eo amin'ny milina eo an-toerana (ny isan'ny segondra nanomboka tamin'ny Janoary 1, 1900), dikan-ny 1-4, fomba - 3 (client mode).

Ny mpizara, rehefa nanaiky ny fangatahana, dia mameno ny saha rehetra ao amin'ny fonosana NTP, mandika amin'ny saha. avy sanda avy amin'ny mamindra, izay tonga tao amin'ny fangatahana. Zava-miafina amiko ny antony tsy ahafahan'ny mpanjifa mameno avy hatrany ny sandan'ny fotoanany amin'ny sehatra avy. Vokatr'izany, rehefa miverina ny fonosana, ny mpanjifa dia manana sanda 4 fotoana - ny fotoana nandefasana ny fangatahana (avy), fotoana nandraisan'ny mpizara ilay fangatahana (Raiso), fotoana nandefasan'ny mpizara ny valiny (mamindra) ary ny fotoana nahazoan'ny mpanjifa ny valiny - tonga (tsy ao anaty fonosana). Amin'ny fampiasana ireo soatoavina ireo dia afaka mametraka ny fotoana mety isika.

Fonosana fandefasana sy fandraisana kaody

# Time difference between 1970 and 1900, seconds
FORMAT_DIFF = (datetime.date(1970, 1, 1) - datetime.date(1900, 1, 1)).days * 24 * 3600
# Waiting time for recv (seconds)
WAITING_TIME = 5
server = "pool.ntp.org"
port = 123
    
packet = NTPPacket(version_number=2, mode=3, transmit=time.time() + FORMAT_DIFF)
answer = NTPPacket()
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    s.settimeout(WAITING_TIME)
    s.sendto(packet.pack(), (server, port))
    data = s.recv(48)
    arrive_time = time.time() + FORMAT_DIFF
    answer.unpack(data)

Fanodinana angona avy amin'ny mpizara

Ny fanodinana angon-drakitra avy amin'ny mpizara dia mitovy amin'ny fihetsik'ilay lehilahy anglisy avy amin'ny olana taloha nataon'i Raymond M. Smullyan (1978): "Tsy nanana famantaranandro ny lehilahy iray, fa nisy famantaranandro marina tao an-trano, izay hadinony indraindray. rivotra. Indray andro, rehefa nanadino ny nanodinkodina ny famantaranandro indray izy, dia nandeha nitsidika ny namany, nandany ny takariva niaraka taminy, ary rehefa nody izy, dia nahavita nametraka tsara ny famantaranandro. Ahoana no nahavitany izany raha tsy fantatra mialoha ny fotoana handehanana? Ny valiny dia izao: “Rehefa miala ao an-trano ny olona iray, dia manodinkodina ny famantaranandrony ary mahatsiaro ny toeran’ny tanana. Rehefa tonga tany amin'ny namany izy ary nandao ny vahiny, dia nanamarika ny fotoana nahatongavany sy niaingany. Izany dia ahafahany mamantatra hoe hafiriana no nitsidika azy. Rehefa niverina tany an-trano sy nijery ny famantaranandro ny olona iray, dia mamaritra ny faharetan'ny tsy fisiany. Amin'ny fanalana amin'io fotoana io ny fotoana laniny mitsidika, ny olona iray dia mahita ny fotoana laniny mankany sy miverina. Amin’ny fampitomboana ny antsasaky ny fotoana lany eny an-dalana ho amin’ny fotoana handaozana ny vahiny, dia mahazo fotoana izy hamantatra ny fotoana hahatongavana any an-trano sy hanitsy ny tànany amin’ny famantaranandrony.”

Tadiavo ny fotoana hiasan'ny mpizara amin'ny fangatahana:

  1. Tadiavo ny fotoana fandehanan'ny fonosana avy amin'ny mpanjifa mankany amin'ny mpizara: ((Tonga – Niainga) – (Mandefa – Mandray)) / 2
  2. Tadiavo ny fahasamihafana misy eo amin'ny fotoanan'ny mpanjifa sy ny mpizara:
    Raiso - Originaire - ((Tonga - Originate) - (Ampitaina - Raiso)) / 2 =
    2 * Raiso – 2 * Originate – Tonga + Originate + Transmit – Raiso =
    Raiso - Originate - Tonga + fandefasana

Ampidirinay amin'ny fotoana eo an-toerana ny vidiny ary hankafy ny fiainana.

Ny vokatra azo

time_different = answer.get_time_different(arrive_time)
result = "Time difference: {}nServer time: {}n{}".format(
    time_different,
    datetime.datetime.fromtimestamp(time.time() + time_different).strftime("%c"),
    answer.to_display())
print(result)

ilaina rohy.

Source: www.habr.com

Add a comment