Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

simple SNTP python script

Tags:

python

I need help to complete following script:

import socket
import struct
import sys
import time

NTP_SERVER = '0.uk.pool.ntp.org'
TIME1970 = 2208988800L

def sntp_client():
    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    data = str.encode('\xlb' + 47 * '\0')
    client.sendto(data, (NTP_SERVER, 123))
    data, addr = client.recvfrom(1024)
    if data:
        print('Response received from:', addr)
    t = struct.unpack('!12I', data)[10]
    t -= TIME1970
    print('\tTime: %s' % time.ctime(t))

if __name__ == '__main__':
    sntp_client()

Expected output:

Response received from: ('80.82.244.120', 123)
      Time: Tue Sep 13 14:49:38 2016

Problem is that program is not giving any output. It looks like it stucks at:

data, addr = client.recvfrom(1024)

I hope someone can help me with this.

like image 562
Harshil Avatar asked Sep 13 '16 09:09

Harshil


2 Answers

Here is the working script from the Second Edition of Python Network Programming Cookbook:

import socket, struct, sys, time

NTP_SERVER = '0.uk.pool.ntp.org'
TIME1970 = 2208988800

def sntp_client():
    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    data = '\x1b' + 47 * '\0'
    client.sendto(data.encode('utf-8'), (NTP_SERVER, 123))
    data, address = client.recvfrom(1024)
    if data: print('Response received from:', address)
    t = struct.unpack('!12I', data)[10] - TIME1970
    print('\tTime = %s' % time.ctime(t))

if __name__ == '__main__':
    sntp_client()
like image 169
Harshil Avatar answered Oct 03 '22 16:10

Harshil


It should be noted that the accepted answer neglects the fraction part of the timestamp, see e.g. IETF RFC5905, p.13. A code snippet including it could look like

import socket
import struct
import datetime

NTP_SERVER = '0.uk.pool.ntp.org'
NTP_DELTA = 2208988800 # given as system epoch (e.g. 1970-1-1) minus NTP epoch (1900-1-1) in [s]

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as client:
    data = '\x1b' + 47 * '\0'
    client.sendto(data.encode('utf-8'), (NTP_SERVER, 123))
    data, _ = client.recvfrom(256)
    tx_s, tx_f = struct.unpack('!12I', data)[10:12] # seconds and fractional seconds
    tx_timestamp = (tx_s + float(tx_f)/2**32) - NTP_DELTA
    
print(datetime.datetime.fromtimestamp(tx_timestamp, datetime.timezone.utc)) 
# e.g.
# 2019-12-18 13:02:14.029521+00:00 # Note: UTC used here for output!

Also keep in mind that this only returns the transmit timestamp (tx; time when the server sent the packet). If you look for the milliseconds, the round trip delay might be signficant (see e.g. p.29 of the linked RFC5905).

Sidenote: the socket docs recommend to open the socket in a with context so that it is closed properly when not needed anymore.

like image 40
FObersteiner Avatar answered Oct 03 '22 17:10

FObersteiner