大量的设备连接到互联网,而设备之间需要通讯以及相互协作,这就要求不同设备之间需要保持时钟同步。然而无论是多么精准的时钟,一旦运行久了后,它指示的时间与真实时间会产生偏差,在假设不同设备启动时时间初始化不同,这就很难保证不同设备之间的时钟频率还能够保持一致。

TCP/IP协议在创建时就已经意识到,不同设备间一旦时钟不同频就可能导致相互协作出现问题。于是就想构造出一套协议让不同设备间相互协商,然后确保设备间在时间上能保持步调一致,而这个任务就落到ICMP协议头上。

发起同步的设备产生一个时间戳,然后利用ICMP消息体和协议规则,将时间戳发送给接收设备,这就是一个timestamp request消息。接收设备收到消息后返回自己的时间戳,这就是timestamp reply 消息。发出者的时间戳和接收者的时间戳就可以让两个设备之间保持时钟同步。

产生ICMP timestamp 消息的应用叫hping,一般来说系统可能不自带,需要我们自行安装,我们macos上安装hping后就可以通过下面命令产生timestamp消息:

sudo hping 192.168.2.1  --icmp --icmp-ts -V

通过wireshark抓包就可以看到消息发送和接收状况:

我们看看timestamp消息的结构:

它其实是我们上次实现ping应用的翻版,只不过多加了几个数据项。其中它的type值域对于request来说要设置成12,对于reply要设置成14,sequence number 和identifier 意义与上一节描述的一样,original timestamp 用于发起者填写自己的当前时间,接下来的两个时间戳由接收者填写,Receive timestamp是接收者收到消息时的时间,Transmit timestamp是接收者回发消息时的时间。

这里可能让人有点出乎意料的是,返回消息中包含两个时间戳而不是一个。这是因为发起者收到返回消息后,它能知道发出消息的接收时间和回应消息的发出时间,这样发起者就能知道消息传达到指定设备需要的时间,从而对当前网络流量有了解,同时指定收到设备的消息处理速度,从而能够根据具体情况决定下面消息发送的速度和流量。

我们看看消息组成的数据格式:

在实践上,即使有这样的协议,不同设备之间的同频依然难以实现。因为ICMP基于IP之上,而IP协议本质上是不可靠的,因此发出去的消息很可能会遗失,抵达不了目的设备,因此如此简单的交换两个设备的时间戳根本保障不了不同设备之间的同步,于是有更强大的协议用于保障时间同步,那就是NTP,以后我们会介绍到。

由于该协议与前面我们实现的ping协议非常相近,因此我们可以在上一节的基础上进行修改就可以完成。首先我们把上一节Ping应用里的createICMPEchoHeader改成createICMPHeader,以便用于继承,然后创建一个新类名为hping,继承自上一节的PingApp:

package Application;import java.nio.ByteBuffer;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.HashMap;
import java.util.TimeZone;import javax.xml.crypto.Data;import protocol.IProtocol;
import protocol.ProtocolManager;public class HPingApp extends PingApp{private int send_time = 0;public HPingApp(int times, byte[] destIP) {super(times, destIP);}protected byte[] createICMPHeader() {IProtocol icmpProto = ProtocolManager.getInstance().getProtocol("icmp");if (icmpProto == null) {return null;}//构造icmp echo 包头HashMap<String, Object> headerInfo = new HashMap<String, Object>();headerInfo.put("header", "timestamp");headerInfo.put("identifier", identifier);headerInfo.put("sequence_number", sequence);sequence++;//获取UTC时间Calendar rightNow = Calendar.getInstance();int hour = rightNow.get(Calendar.HOUR_OF_DAY);int minutes = rightNow.get(Calendar.MINUTE);int secs = rightNow.get(Calendar.SECOND);send_time = (hour * 3600 + minutes * 60 + secs) * 1000;headerInfo.put("original_time", send_time);int receive_time = 0, transmit_time = 0;headerInfo.put("receive_time", receive_time);headerInfo.put("transmit_time", transmit_time);byte[] icmpEchoHeader = icmpProto.createHeader(headerInfo);return icmpEchoHeader;}public void handleData(HashMap<String, Object> data) {short sequence = (short)data.get("sequence");int receive_time = (int)data.get("receive_time");System.out.println("receive time  for timestamp request " + sequence + "for  " + (send_time - receive_time) / 1000 + "secs");int transmit_time = (int)data.get("transmit_time");System.out.println("receive reply for ping request " + sequence + "for  " + (send_time - transmit_time) / 1000 + "secs");}
}

接下来我们创建一个构造ICMP tiemstamp request 协议包头的类:

package protocol;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Random;import jpcap.packet.Packet;
import utils.Utility;public class ICMPTimeStampHeader implements IProtocol{private static int ICMP_TIMESTAMP_HEADER_LENGTH = 20;private static byte ICMP_TIMESTAMP_REQUEST_TYPE = 13;private static byte ICMP_TIMESTAMP_REPLY_TYPE = 14;private static short ICMP_ECHO_IDENTIFIER_OFFSET = 4;private static short ICMP_ECHO_SEQUENCE_NUM_OFFSET = 6;private static short ICMP_ORIGINAL_TIMESTAMP_OFFSET = 8;private static short ICMP_RECEIVE_TIMESTAMP_OFFSET = 12;private static short ICMP_TRANSMIT_TIMESTAMP_OFFSET = 16;@Overridepublic byte[] createHeader(HashMap<String, Object> headerInfo) {String headerName = (String)headerInfo.get("header");if (headerName != "timestamp") {return null;}int bufferLen = ICMP_TIMESTAMP_HEADER_LENGTH;byte[] buffer = new byte[bufferLen ];ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);byte type = ICMP_TIMESTAMP_REQUEST_TYPE;byteBuffer.put(type);byte code = 0;byteBuffer.put(code);short checkSum = 0;byteBuffer.order(ByteOrder.BIG_ENDIAN);byteBuffer.putShort(checkSum);short identifier = 0;if (headerInfo.get("identifier") == null) {Random ran = new Random();identifier = (short) ran.nextInt();headerInfo.put("identifier", identifier);}identifier = (short) headerInfo.get("identifier");byteBuffer.order(ByteOrder.BIG_ENDIAN);byteBuffer.putShort(identifier);short sequenceNumber = 0;if (headerInfo.get("sequence_number") != null) {sequenceNumber = (short) headerInfo.get("sequence_number");}headerInfo.put("sequence_number", sequenceNumber);byteBuffer.order(ByteOrder.BIG_ENDIAN);byteBuffer.putShort(sequenceNumber);if (headerInfo.get("original_time") != null) {int original_time = (int)headerInfo.get("original_time");byteBuffer.putInt(original_time);}if (headerInfo.get("receive_time") != null) {int receive_time = (int)headerInfo.get("receive_time");byteBuffer.putInt(receive_time);}if (headerInfo.get("transmit_time") != null) {int transmit_time = (int)headerInfo.get("transmit_time");byteBuffer.putInt(transmit_time);}checkSum = (short) Utility.checksum(byteBuffer.array(), byteBuffer.array().length);byteBuffer.order(ByteOrder.BIG_ENDIAN);byteBuffer.putShort(2, checkSum);System.out.println("ICMP timestamp header, checksum: " + String.format("0x%08x", checkSum));return byteBuffer.array();}@Overridepublic HashMap<String, Object> handlePacket(Packet packet) {ByteBuffer buffer = ByteBuffer.wrap(packet.header);if (buffer.get(0) != ICMP_TIMESTAMP_REPLY_TYPE) {return null;}HashMap<String, Object> header = new HashMap<String, Object>();header.put("identifier", buffer.getShort(ICMP_ECHO_IDENTIFIER_OFFSET));header.put("sequence", buffer.getShort(ICMP_ECHO_SEQUENCE_NUM_OFFSET));header.put("original_time", buffer.getInt(ICMP_ORIGINAL_TIMESTAMP_OFFSET));header.put("receive_time", buffer.getInt(ICMP_RECEIVE_TIMESTAMP_OFFSET));header.put("transmit_time", buffer.getInt(ICMP_TRANSMIT_TIMESTAMP_OFFSET));return header;}}

然后在ICMPProtocolLayer中添加上面的对象:

 public ICMPProtocolLayer() {//增加icmp echo 协议包头创建对象protocol_header_list.add(new ICMPEchoHeader());protocol_header_list.add(new ICMPTimeStampHeader());}

完成代码后,我们将请求发送给本地路由器,然后通过wireshark抓包可以看到发出去的消息如下图:

回复消息如下图:

更多视频讲解和代码调试演示请参看视频:
更详细的讲解和代码调试演示过程,请点击链接

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:

ICMP timestamp 协议原理和实现相关推荐

  1. 计算机网络——ICMP/IGMP协议原理

    摘要 ICMP全称是Internet Control Message Protocol,也就是互联网控制报文协议.网络包在复杂的网络传输环境里,常常会遇到各种问题.当遇到问题的时候,总不能死个不明不白 ...

  2. 计算机网络——HTTP协议原理

    摘要 在日常的开发中,很多开发的同学可能很少了解的HTTP协议的底层原理.HTTP协议的底层涉及到请求响应模型,HTTP的工作流程.cookie和session的原理等.本博文主要介绍计算机网络中HT ...

  3. 透析ICMP协议(一): 协议原理

    透析ICMP协议(一): 协议原理 =============================== 这篇文章原创自bugfree/CSDN 平台: VC6 Windows XP ICMP简介: --- ...

  4. 计算机网络路由选择协议,IP路由选择协议原理和作用

    IP路由选择协议原理和作用 (2008-10-20 19:26:17) 标签: 杂谈 IP路由选择 如果目的主机与源主机直接相连或都在一个共享网络上,那就直接把包发送到目的主机, 如果不是,那把ip数 ...

  5. 100行源代码搞定用户态协议栈丨udp,icmp,arp协议的现实丨网络协议栈丨Linux服务器开发丨C++后端开发丨Linux后台开发

    100行源代码搞定用户态协议栈 视频讲解如下,点击观看: 100行源代码搞定用户态协议栈丨udp,icmp,arp协议的现实丨网络协议栈丨Linux服务器开发丨C++后端开发丨Linux后台开发丨网络 ...

  6. 在您的防火墙上过滤外来的ICMP timestamp(类型 13) 如何处理?

    收到安全厂商的评估报告,线上一台CentOS的系统被告知漏洞如下: 漏洞名称 ICMP时间戳检测(原理扫描) 受影响IP 192.168.31.1 漏洞等级 信息 CVE编号 CVE-1999-052 ...

  7. OpenFlow协议原理及基本配置-网络测试仪实操

    一.OpenFlow协议原理 1.OpenFlow技术背景 ●转发和控制分离是SDN网络的本质特点之一.在SDN网络架构中,控制平面与转发平面分离,网络的管理和状态在逻辑上集中到一起,底层的网络基础从 ...

  8. ICMP隧道通信原理与通信特征

    一 ICMP 隧道技术解析 ICMP协议 ICMP(InternetControl MessageProtocol)Internet控制报文协议.它是TCP/IP协议簇的一个子协议,用于在IP主机.路 ...

  9. Zookeeper ZAB协议原理浅析

    文章目录 前言 1. 基本角色和概念 2. Leader Election 3. Discovery 4. Synchronization 5. BroadCast 后记 前言 DTCC 要在下周一到 ...

最新文章

  1. UICollectionView之网络图片解析
  2. c++语言程序设计案...,C++程序设计案.ppt
  3. 小程序影藏溢出的gif_ScreenToGif:一款小巧实用动图gif制作神器
  4. OpenCV学习笔记(十三):霍夫变换:HoughLines(),HoughLinesP(),HoughCircles( )
  5. mysql 查询效率测试,mysql innode和myisam引擎查询性能比较测试
  6. mysql 过滤单引号_python实现mysql的单引号字符串过滤方法
  7. 2021年面试前端岗位需要注意什么?
  8. spark生态及各个功能
  9. 基于CarMaker的C-NCAP主动安全系统试验仿真(四)
  10. Unity 基础资源知识汇总学习
  11. java7 3dm下载_3DM游戏运行库合集安装包v2.8
  12. Linux指令——tailf
  13. 批量创建文件夹-批处理(一)
  14. 大学生mysql实训心得_大学生实训心得与收获
  15. codecombat极客战记森林61-70通关代码
  16. cannot import name '_validate_lengths' from 'numpy.lib.arraypad'
  17. uc浏览器电脑版翻译设置在哪 uc浏览器翻译网页教程
  18. php中的汉字转化为拼音,简繁体转化
  19. 融云聊天室属性 kv
  20. 中国人工智能城市排名榜公布,北京、杭州、深圳居前

热门文章

  1. POI操作Excel实现导出
  2. java计算机毕业设计 高考志愿填报系统 高考志愿推荐系统 高考志愿填报辅助系统 ssm高考填报系统 志愿填报机器人 高考学校实景3D地图(java+ssm+百度地图+实景3D地图)
  3. 比较简单的nginx搭建静态资源linux服务器教程
  4. 面试经验之:蚂蚁饿了么抖音美团等多家面试问题!简历优化等
  5. 7-6 重要的话说三遍(5 分)
  6. 云存储——360云盘
  7. mysql 日期比较_详解Mysql中日期比较大小的方法
  8. 文科计算机有哪些专业,计算机有哪些专业
  9. HTML/Javascript game start menu:游戏开始界面(附代码)
  10. 建立数据驱动的人力资源管理:以红海云eHR系统为例