Lab 12: Network Socket Programming with Python
Overview
In this lab, you will use the Python programming language to implement a simple NTP (Network Time Protocol) client that determines the discrepancy between your computer's time and a NTP server.
References
There are a number of official and un-official references for Python that you may find useful. Be warned, however, that Python syntax and libraries have changed between version 2.x and 3.x. Thus, for this lab, you should prefer newer Python 3.x references where possible.
- Official - Python documentation (for Python 3.x)
- Official - Python Standard Library documentation (for Python 3.x)
- Official - Python sockets documentation (for Python 3.x)
- TutorialsPoint Python Examples
- Differences between Python 2.x and 3.x
- Google University Python Tutorial (written for the older Python 2.7 syntax, but still useful)
- Python Sockets Examples (written for the older Python 2.7 syntax, but still useful)
Lab - Getting Started
To begin this lab, start by obtaining the necessary boilerplate code. Enter the class repository:
unix> cd ~/bitbucket/2013_fall_ecpe170_boilerplate/
Pull the latest version of the repository, and update your local copy of it:
unix> hg pull
unix> hg update
Copy the files you want from the class repository to your private repository:
(In this case, you will copy four flies)
unix> cp ~/bitbucket/2013_fall_ecpe170_boilerplate/lab12/* ~/bitbucket/2013_fall_ecpe170/lab12/
Enter your private repository now, specifically the lab12 folder:
unix> cd ~/bitbucket/2013_fall_ecpe170/lab12
Also, copy the file sample_data_file.dat from Lab 9 into this folder. You will use it in Part 3. Add these files to version control in your private repository (do not add the file packet.binary):
unix> hg add demo.py ntpdate.py sample_data_file.dat
Commit the new files in your personal repository, so you can easily go back to the original starter code if necessary
unix> hg commit -m "Starting Lab 12 with boilerplate code"
Push the new commit to the bitbucket.org website
unix> hg push
Lab Submission:
(1) All source code and lab report PDF must be submitted via Mercurial. Place the source files inside the lab12 folder that was previously created.
Lab Part 1 - Python Setup
Install the latest (3.2+) version of Python. Typically, Ubuntu distributions only come with the older (but still widely used) 2.x Python. We don't care about backwards compatibility, so full speed ahead!
unix> sudo apt-get install python3
Verify that Python is working. Ask it to print the version number, which will be useful in debugging errors/quirks later: Note: This is a CAPITAL letter V!
unix> python3 -V
The output should be similar to: Python 3.2.3
Lab Part 2 - Goodbye World
Using your favorite text editor, create a file (goodbye.py) with the not-so-usual "Goodbye World" code (since this is the last lab of the course):
#!/usr/bin/python3
print("Goodbye World")
Mark the file as "executable" so you can run it as a program:
unix> chmod +x goodbye.py
Now execute the Python program:
unix> ./goodbye.py
Check goodbye.py into version control when finished.
Lab Report:
(1) What is the line that starts with #! doing? Where in ECPE 170 have you seen this before?
Lab Part 3 - Python Basic Skills
Modify the Python3 program demo.py. This program should be invoked via:
unix> ./demo.py <argument1> <argument2>
Demonstrate your knowledge of fundamental Python skills by performing the following operations in the program:
- Determine how many arguments have been provided to the script on the command line. If there are two arguments (*not* including the program name itself), print them out one at a time. Otherwise, exit immediately.
- Check whether the second argument is an integer, and if not print an error message and exit. (Note: each argument is a string, so you need to determine whether the value in the string is an integer). Assign the integer to the variable count.
- Concatenate the two string arguments together, save them to a new variable called onestring, and then print onestring.
- Open the file sample_data_file.dat for reading, in binary mode.
- Skip over count-1 records in the file.
- Read the four values in the target record, and do a sanity check as in Lab 9.
Note: This demo program can be very short! No need to get fancy - save that for the NTP client.
Check demo.py into version control when finished.
Lab Part 4 - NTP Basic Skills
Before writing a program that communicates with an NTP server, you are going to manually test your knowledge of ntpdate. The netcat client program allows you to open a UDP or TCP socket to a port and transfer data. In this example, it will send data from a file and output the received data to the console, which will then be interpreted using xxd.
To invoke the netcat client to connect to a server 0.pool.ntp.org in the NTP server pool on port 123:
unix> netcat -q 1 -u 0.pool.ntp.org 123 < packet.binary | xxd -g 4
The -u tells netcat to open a UDP connection to the server. It then sends the contents of packet.binary. The response is piped to xxd, which breaks it into 4-byte words on the standard output. netcat will wait for 1 second before exiting.
The format of the data is described in RFC 5905: "Network Time Protocol Version 4: Protocol and Algorithms Specification". A correct response from an NTP server is always the same number of bytes. The first two bytes will always be 0x24 and 0x02 for our situation, while most of the other bytes will be different each time you run the program. The fourth word returned, the reference ID field, is normally the IPV4 address of the server. The remaining words are time values represented in 64-bit fixed-precision; the first word is the integer portion of the seconds and the second word the "fractional" portion, representing 1/232 second or approximately 232 picoseconds. The seconds represent the elapsed time from the start of the"prime epoch", defined as midnight UTC (Coordinated Universal Time) on January 1st, 1900.
Lab Report:
(2) Document the request output by xxd to the netcat command.
(By "document", you should provide the full server response, which will be a few lines on the screen. Copy everything; this way I know you got the right response.
(3) Repeat the request and document the second response.
(4) By reading RFC 5905 or searching on the internet, determine which 64-bits of the NTP server's response is the receive timestamp. Use this value to calculate the number of seconds since the prime epoch, including the fractional part.
Tip: Tired of important text scrolling off the top of your terminal window? Adjust the "scrollback" option. Go to Edit->Profile Preferences->Scrolling and set the scrollback to "Unlimited" (via the check box) or at least set it to a large fixed number. (2048 lines? 4096 lines?)
Lab Part 5 - NTP Client
Write a Python3 program called ntpdate.py which queries the current time from an server via the NTP protocol and determines the discrepancy between your computer and the server:
unix> ./ntpdate.py
A Python module which implements the NTP protocol named ntplib exists already. Be warned, however: You *cannot* use it for this lab, and zero points will be awarded if you do! The reason for not using this module is because it hides the details of the NTP protocol, and the purpose of this lab is to actually learn about the protocol operation. Instead, you must use the lower-level socket module.
Tip: There is substantial boilerplate code provided for this exercise, and further instructions and hints contained within.
Note: the system time is normally updated each time you boot Ubuntu, so you should not notice a large discrepancy between your time and the NTP server's time. If you want to see a larger discrepancy, you can use the date command to manually set the date and time. For example, to set the date and time to 4:27am, Nov 20th, you would type:
unix> /bin/date 11200427
You can use the man command to get a full explanation of the arguments for date. Be careful, however, about making large changes in time, as some things on the system might become unstable.
Lab Report:
(5) Document the output from your program ntpdate.py command by pasting into the report. Repeat for three executions.
Check ntpdate.py into version control when finished.
Lab Report - Wrapup:
(1) What was the best aspect of this lab?
(2) What was the worst aspect of this lab?
(3) How would you suggest improving this lab in future semesters?