Synchronize Time with a PTP Server in C#
Precision Time Protocol (PTP) is a network protocol used to synchronize clocks in a distributed system. In this tutorial, we will create a PTP client that can synchronize the time with a PTP server using the Simple Network Time Protocol (SNTP) as the PTP transport protocol.
Before we start, you need to have the following installed on your computer:
- Visual Studio (or any other C# IDE)
- .NET Framework (version 4.6.1 or later)
Let’s get started
- Create a new C# console application in Visual Studio.
- Add the
System.Net
andSystem.Net.Sockets
namespaces to your project.
The code
Here’s the code for the PTP client:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
class PtpClient
{
private const int PtpServerPort = 319;
private const int PtpVersionNumber = 2;
private UdpClient udpClient;
private IPEndPoint ptpServerEndPoint;
private byte[] buffer;
public PtpClient(string ptpServerIp)
{
udpClient = new UdpClient();
ptpServerEndPoint = new IPEndPoint(IPAddress.Parse(ptpServerIp), PtpServerPort);
buffer = new byte[48];
buffer[0] = (byte)((PtpVersionNumber << 4) | 3); // PTP version number and message type
}
public DateTime SynchronizeTime()
{
udpClient.Send(buffer, buffer.Length, ptpServerEndPoint);
IPEndPoint senderEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] receiveBuffer = udpClient.Receive(ref senderEndPoint);
// Get the transmit timestamp from the PTP server response
long transmitTimestamp = BitConverter.ToInt64(receiveBuffer, 40);
// Convert the transmit timestamp to a DateTime object
DateTime dateTime = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
dateTime = dateTime.AddSeconds(transmitTimestamp >> 32);
dateTime = dateTime.AddSeconds((transmitTimestamp & 0xffffffffL) / 4294967296.0 * 1000000000);
return dateTime;
}
public void Dispose()
{
udpClient?.Close();
}
}
Let’s go through the code step-by-step:
- The
PtpClient
class is defined with the following private fields:udpClient
– an instance of theUdpClient
class used to send and receive PTP messages.ptpServerEndPoint
– an instance of theIPEndPoint
class that represents the IP address and port number of the PTP server.buffer
– a byte array used to store the PTP message.
- The
PtpClient
constructor takes a string argument that represents the IP address of the PTP server. The constructor initializes theudpClient
andptpServerEndPoint
fields and sets the first byte of thebuffer
to the PTP version number and message type. - The
SynchronizeTime
method is used to send a PTP message to the server and receive the response. It does the following:- Sends the PTP message using the
Send
method of theudpClient
object. - Receives the PTP response using the
Receive
method of theudpClient
object.
- Sends the PTP message using the
- The
transmitTimestamp
is extracted from the PTP response by getting the last 8 bytes of the response. - The
transmitTimestamp
is converted to aDateTime
object using the following steps:- The
DateTime
object is initialized with the Unix epoch time (January 1, 1900). - The seconds component of the
DateTime
object is set to the high 32 bits of thetransmitTimestamp
. - The fractional seconds component of the
DateTime
object is set to the low 32 bits of thetransmitTimestamp
divided by the maximum value of a 32-bit integer (4294967296) multiplied by 1000000000 (the number of nanoseconds in a second).
- The
- The
SynchronizeTime
method returns theDateTime
object representing the current time on the PTP server. - The
Dispose
method is used to close theudpClient
object when thePtpClient
object is no longer needed.
Usage
Here’s an example of how to use the PtpClient
class to synchronize the time with a PTP server:
using System;
class Program
{
static void Main(string[] args)
{
PtpClient client = new PtpClient("ptp.example.com");
try
{
DateTime ptpTime = client.SynchronizeTime();
Console.WriteLine("PTP server time: " + ptpTime.ToString());
}
catch (Exception ex)
{
Console.WriteLine("Error synchronizing time: " + ex.Message);
}
finally
{
client.Dispose();
}
Console.ReadLine();
}
}
Conclusion
In this tutorial, we created a PTP client that can synchronize the time with a PTP server using the Simple Network Time Protocol (SNTP) as the PTP transport protocol. The PtpClient
class sends a PTP message to the server and receives the response, extracts the transmit timestamp from the response, and converts it to an DateTime
object representing the current time on the PTP server. You can use the PtpClient
class to synchronize the time with a PTP server in your own C# applications.