Recipe 13.4. Getting Time from a Server via the SNTP Protocol
Credit: Simon Foster
Problem
You need to contact
an SNTP (Simplified Network Time Protocol) server (which respects RFC
2030) to obtain the time of day as returned by that server.
Solution
SNTP is quite simple to implement, for example in a small script:
import socket, struct, sys, time
TIME1970 = 2208988800L # Thanks to F.Lundh
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
data = '\x1b' + 47 * '\0'
client.sendto(data, (sys.argv[1], 123))
data, address = client.recvfrom(1024)
if data:
print 'Response received from:', address
t = struct.unpack('!12I', data)[10]
t -= TIME1970
print '\tTime=%s' % time.ctime(t)
Discussion
An SNTP exchange begins with a client
sending a 48-byte UDP datagram which starts with byte
'\x1b'. The server answers with a 48-byte UDP
datagram made up of twelve network-order longwords (4 bytes each). We
can easily unpack the server's returned datagram
into a tuple of ints, by using
standard Python library module
struct's
unpack function. Then, for simplicity, we look
only at the eleventh of those twelve longwords. That integer gives
the time in secondsbut it measures time from an epoch
that's different from the 1970-based one normally
used in Python. The difference in epochs is easily fixed by
subtracting the magic number (kindly supplied by
F. Lundh) that is named TIME1970 in the recipe.
After the subtraction, we have a time in seconds from the epoch that
complies with Python's standard
time module, and we can handle it with the
functions in module time. In this recipe, we just
display it on standard output as formatted by function
time.ctime.
See Also
Documentation for the standard library modules
socket, struct and
time in the Library
Reference and Python in a
Nutshell; the SNTP protocol is defined in RFC 2030
(http://www.ietf.org/rfc/rfc2030.txt), and the
richer NTP protocol is defined in RFC 1305 (http://www.ietf.org/rfc/rfc1305.txt); Chapter 3 for general issues dealing with time in
Python.