سلام، حبرهاب استعمال ڪندڙ. اڄ مان توهان جي پنهنجي سادي اين ٽي پي ڪلائنٽ لکڻ بابت ڳالهائڻ چاهيان ٿو. اسان بنيادي طور تي پيڪٽ جي جوڙجڪ ۽ اين ٽي پي سرور کان جوابن کي ڪيئن پروسيس ڪجي ان تي بحث ڪنداسين. ڪوڊ پٿون ۾ لکيو ويندو، ڇاڪاڻ ته مون کي يقين آهي ته هن قسم جي شيءِ لاءِ ڪا به بهتر ٻولي ناهي. جيڪي ماڻهو موضوع سان واقف آهن اهي اين ٽي پليب سان هڪجهڙائي محسوس ڪندا - مان ان کان متاثر ٿيس.
تنهن ڪري، اين ٽي پي ڇا آهي؟ اين ٽي پي هڪ پروٽوڪول آهي جيڪو صحيح وقت جي سرورن سان لهه وچڙ ۾ اچي ٿو. هي پروٽوڪول ڪيترن ئي جديد مشينن ۾ استعمال ٿيندو آهي. مثال طور، ونڊوز ۾ w32tm سروس.
اين ٽي پي پروٽوڪول جا ڪل 5 نسخا آهن. پهريون، نسخو 0 (1985، RFC958)، هن وقت متروڪ سمجهيو ويندو آهي. نوان نسخا هن وقت استعمال ۾ آهن: نسخو 1 (1988، RFC1059)، نسخو 2 (1989، RFC1119)، نسخو 3 (1992، RFC1305)، ۽ نسخو 4 (1996، RFC2030). نسخو 1-4 هڪ ٻئي سان مطابقت رکن ٿا؛ اهي صرف انهن جي آپريٽنگ الگورتھم ۾ مختلف آهن. سرور.
پيڪيج فارميٽ

ليپ انڊيڪيٽر (اصلاح جو اشارو) - هڪ انگ جيڪو ليپ سيڪنڊ وارننگ کي ظاهر ڪري ٿو. مطلب:
- 0 - ڪابه اصلاح نه
- 1 - ڏينهن جو آخري منٽ 61 سيڪنڊن تي مشتمل آهي.
- 2 - ڏينهن جو آخري منٽ 59 سيڪنڊن تي مشتمل آهي.
- 3 - سرور جي خرابي (وقت هم وقت نه ٿيو آهي)
نسخه نمبر (ورجن نمبر) – اين ٽي پي پروٽوڪول ورجن نمبر (1-4).
فيشن (موڊ) — پيڪٽ موڪليندڙ جو آپريٽنگ موڊ. 0 کان 7 تائين قدر، سڀ کان عام:
- 3 - گراهڪ
- 4 - سرور
- 5 - نشريات جو طريقو
اسٽريم (ليئرنگ ليول) - سرور ۽ ريفرنس ڪلاڪ جي وچ ۾ وچولي پرتن جو تعداد (1 - سرور سڌو سنئون ريفرنس ڪلاڪ مان ڊيٽا وٺندو آهي، 2 - سرور ليول 1 تي سرور کان ڊيٽا وٺندو آهي، وغيره).
تلاء — هڪ دستخط ٿيل عدد جيڪو لڳاتار پيغامن جي وچ ۾ وڌ ۾ وڌ وقفي جي نمائندگي ڪري ٿو. اين ٽي پي ڪلائنٽ هتي اهو وقفو بيان ڪري ٿو جنهن تي اهو سرور کي پول ڪرڻ جي اميد رکي ٿو، ۽ اين ٽي پي سرور اهو وقفو بيان ڪري ٿو جنهن تي اهو پول ٿيڻ جي اميد رکي ٿو. قدر سيڪنڊن جي بائنري لوگارٿم جي برابر آهي.
سڌائي (precision) — هڪ دستخط ٿيل عدد جيڪو سسٽم ڪلاڪ جي درستگي جي نمائندگي ڪري ٿو. قدر سيڪنڊ جي بائنري لوگارٿم جي برابر آهي.
روٽ دير (سرور ليٽنسي) - اهو وقت جيڪو ڪلاڪ ريڊنگز کي NTP سرور تائين پهچڻ ۾ لڳندو آهي، مقرر پوائنٽ سيڪنڊن جي تعداد جي طور تي.
جڙ جي پکيڙ (سرور ڪلاڪ اسپريڊ) — اين ٽي پي سرور ڪلاڪ اسپريڊ مقرر پوائنٽ سيڪنڊن جي تعداد جي طور تي.
حوالو سڃاڻپ (ذريعو سڃاڻپ ڪندڙ) - گھڙي جي سڃاڻپ. جيڪڏهن سرور وٽ اسٽريٽم 1 آهي، ته پوءِ ريف آئي ڊي ايٽمي ڪلاڪ جو نالو آهي (4 ASCII اکر). جيڪڏهن سرور ٻيو سرور استعمال ڪري ٿو، ته پوءِ ريف آئي ڊي ۾ ان سرور جو پتو شامل آهي.
آخري 4 فيلڊ وقت جي نمائندگي ڪن ٿا - 32 بِٽ - انٽيجر حصو، 32 بِٽ - فريڪشنل حصو.
حوالي — سرور تي تازيون ڪلاڪ ريڊنگون.
بڻيو - اهو وقت جڏهن پيڪٽ موڪليو ويو (سرور طرفان ڀريو ويو - ان بابت وڌيڪ هيٺ ڏنل).
وصول ڪريو - سرور پاران پيڪٽ جي وصولي جو وقت.
ڏيون - جڏهن پيڪٽ سرور کان ڪلائنٽ ڏانهن موڪليو ويو (ڪلائنٽ پاران ڀريو ويو، ان بابت وڌيڪ هيٺ).
اسين آخري ٻن شعبن تي غور نه ڪنداسين.
اچو ته پنهنجو پيڪيج لکون:
پيڪيج ڪوڊ
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
سرور ڏانهن پيڪٽ موڪلڻ (۽ وصول ڪرڻ) لاءِ، اسان کي ان کي بائيٽس جي صف ۾ تبديل ڪرڻ جي قابل هجڻ گهرجي.
هن (۽ ريورس) آپريشن لاءِ، اسين ٻه فنڪشن لکنداسين - pack() ۽ unpack():
پيڪ فنڪشن
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))
ان پيڪ فنڪشن
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
سست ماڻهن لاءِ، هتي ڪوڊ جو هڪ اپينڊڪس آهي جيڪو هڪ پيڪٽ کي هڪ سٺي اسٽرنگ ۾ تبديل ڪري ٿو.
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)
سرور ڏانهن هڪ پيڪٽ موڪلڻ
ڀريل خانن سان هڪ پيڪٽ سرور ڏانهن موڪليو وڃي. نسخو, فيشن и ڏيون. جي ڏيون توهان کي مقامي مشين تي موجوده وقت (1 جنوري 1900 کان سيڪنڊن جو تعداد)، نسخو - 1-4 مان ڪو به، موڊ - 3 (ڪلائنٽ موڊ) بيان ڪرڻ گهرجي.
سرور، درخواست قبول ڪرڻ کان پوءِ، اين ٽي پي پيڪٽ ۾ سڀني فيلڊز کي ڀريندو آهي، انهن کي فيلڊ ۾ ڪاپي ڪندو آهي. بڻيو مطلب مان ڏيون، جيڪو درخواست ۾ آيو هو. اهو مون لاءِ هڪ راز آهي ته ڪلائنٽ فوري طور تي فيلڊ ۾ پنهنجو وقت ڇو نٿو ڀري سگهي. بڻيونتيجي طور، جڏهن پيڪٽ واپس ايندو آهي، ڪلائنٽ وٽ 4 وقت جا قدر هوندا آهن - درخواست موڪلڻ جو وقت (بڻيو)، جڏهن سرور پاران درخواست ملي هئي (وصول ڪريو)، سرور کي جواب موڪلڻ ۾ لڳل وقت (ڏيون) ۽ ڪلائنٽ کي جواب حاصل ڪرڻ ۾ لڳندڙ وقت - پهچڻ (پيڪيج ۾ نه). انهن قدرن کي استعمال ڪندي، اسان صحيح وقت مقرر ڪري سگهون ٿا.
پيڪٽ موڪلڻ ۽ وصول ڪرڻ لاءِ ڪوڊ
# 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)
سرور کان ڊيٽا پروسيسنگ
سرور مان ڊيٽا پروسيسنگ ڪرڻ، ريمنڊ ايم. سموليان (1978) جي پراڻي مسئلي ۾ انگريز شريف ماڻهوءَ جي عملن جي برابر آهي: "هڪ ماڻهوءَ وٽ ڪا به کلائي واري گھڙي نه هئي، پر هن وٽ گهر ۾ هڪ صحيح ڀت واري گھڙي هئي، جنهن کي هو ڪڏهن ڪڏهن وائن ڪرڻ وساري ڇڏيندو هو. هڪ ڏينهن، پنهنجي گھڙي کي وائن ڪرڻ وساري ڇڏڻ کان پوءِ، هو هڪ دوست سان ملڻ ويو، ان سان شام گذاري، ۽ گهر واپس اچڻ تي، واچ کي صحيح طرح سان سيٽ ڪرڻ ۾ ڪامياب ٿي ويو. جيڪڏهن سفر جو وقت اڳ ۾ معلوم نه هجي ها ته هو اهو ڪيئن منظم ڪندو؟" جواب آهي: "گهر ڇڏڻ وقت، ماڻهو پنهنجي گھڙي کي گھمائيندو آهي ۽ هٿن جي پوزيشن کي ياد ڪندو آهي. جڏهن هو پنهنجي دوست جي جاءِ تي پهچندو آهي ۽ پارٽي ڇڏيندو آهي، هو پنهنجي آمد ۽ روانگي جو وقت نوٽ ڪندو آهي. اهو هن کي اهو معلوم ڪرڻ جي اجازت ڏئي ٿو ته هن پارٽي ۾ ڪيترو وقت گذاريو. گهر واپس اچڻ ۽ پنهنجي گھڙي کي ڏسڻ تي، ماڻهو پنهنجي غير موجودگي جي ڊيگهه جو تعين ڪندو آهي. هن وقت مان پارٽي ۾ گذاريل وقت کي گھٽائڻ سان، ماڻهو گول سفر جي سفر ۾ گذاريل وقت ڳولي ٿو. پارٽي ڇڏڻ جي وقت ۾ روڊ تي گذاريل وقت جو اڌ حصو شامل ڪرڻ سان، هن کي پنهنجي گهر پهچڻ جو وقت معلوم ڪرڻ ۽ پنهنجي گھڙي جي هٿن کي ان مطابق ترتيب ڏيڻ جو موقعو ملندو آهي."
اسان سرور پاران درخواست جي پروسيسنگ ۾ خرچ ڪيل وقت ڳوليون ٿا:
- اسان ڪلائنٽ کان سرور تائين پيڪٽ جي سفر جو وقت ڳوليون ٿا: ((پهچ - شروع ڪريو) - (منتقل ڪريو - وصول ڪريو)) / 2
- اسان ڪلائنٽ ۽ سرور جي وقت جي وچ ۾ فرق ڳوليون ٿا:
وصول ڪريو - شروع ڪريو - ((پهچ - شروع ڪريو) - (منتقل ڪريو - وصول ڪريو)) / 2 =
2 * وصول ڪريو - 2 * شروع ڪريو - پهچ + شروع ڪريو + منتقل ڪريو - وصول ڪريو =
حاصل ڪرڻ - شروع ڪرڻ - پهچڻ + پهچائڻ
اسان نتيجي ۾ مليل قدر کي مقامي وقت ۾ شامل ڪريون ٿا ۽ زندگي مان لطف اندوز ٿيون ٿا.
نتيجي جو نتيجو
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)
مفيد .
جو ذريعو: www.habr.com
