编程实现基于UDP的
PING
The document was finally revised on 2021
计算机网络课程设计
课程名称 计算机网络课程设计 学 院 计算机学院 专业班级 学 号 学生姓名 指导教师 梁路
年 月 日
计算机网络课程设计任务书
设计题目 编程实现基于UDP的PING (Java) 1.编程实现PING的服务器端和客户端,实现操作系统提供的ping命令的类似功能。 2.服务器端PingServer功能: 可以并发地为多个用户服务; 显示用户通过客户端发送来的消息内容(包含头部和payload); 能够模拟分组的丢失;能够模拟分组传输延迟; 将用户发送来的请求request在延迟一段随机选择的时间(小于1s)后返回给客户端,作为收到请求的响应reply; 通过如下命令行启动服务器:java PingServer port。 port为PingServer的工作端口号 3.客户端PingClient功能: 启动后发送10个request。发送一个request后,最多等待1秒以便接收PingServer返回的reply消息。如果在该时间内没有收到服务器的reply,则认为该请求或对该请求的reply已经丢失;在收到reply后立即发送下一个request。 请求消息的payload中至少包含关键字PingUDP、序号、时间戳等内容。如:PingUDP SequenceNumber TimeStamp CRLF 其中:CRLF表示回车换行符(0X0D0A);TimeStamp为发送该消息的机器时间。 为每个请求计算折返时间(RTT),统计10个请求的平均RTT、最大/小RTT。 通过如下命令行启动:java PingClient host port。 host为PingServer所在的主机地址;port为PingServer的工作端口号 1.学习ICMP,了解ping命令的工作机理; 2.学习Java UDP Socket通信机制; 3.了解Java多线程程序设计; 4.服务器PingServer程序设计; 5.客户端PingClient程序设计。 6.调试与演示 命令工作机制学习 2小时 UDP Socket通信机制 2小时 多线程程序设计 4小时 程序设计 6小时 程序设计 12小时 6.调试与演示 4小时 6.课程设计说明书 10小时 已知技术参数和设计要求 设计内容与步骤 设计工作计划与进度安排 目录:
1. 基础知识:
1.1. ICMP
ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
ICMP协议是一种面向无连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。
1.2. Ping
PING是DOS命令,一般用于检测网络通与不通,也叫时延,其值越大,速度越慢PING(PacketInternetGrope),因特网包探索器,用于测试网络连接量的程序。Ping发送一个ICMP回声请求消息给目的地并报告是否收到所希望的ICMP回声应答。它是用来检查网络是否通畅或者网络连接速度的命令。作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:网络上的机器都有唯一确定的IP地址,我们给目标IP地址发送一个数据包,对方就要返回一个同样大小的数据包,根据返回的数据包我们可以确定目标主机的存在,可以初步判断目标主机的操作系统等。
Ping是Windows系列自带的一个可执行命令。利用它可以检查网络是否能够连通,用好它可以很好地帮助我们分析判定网络故障。应用格式:PingIP地
址。该命令还可以加许多参数使用,具体是键入Ping按回车即可看到详细说明。ping指的是端对端连通,通常用来作为可用性的检查。
1.3. UDP
UDP是User Datagram Protocol的简称,中文全称是用户数据包协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。在网络中它与TCP协议一样用于处理数据包。在OSI模型中,UDP协议在第四层——传输层,处于IP协议的上一层。与TCP相比,UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。
(1)UDP是一个无连接协议
(2)由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
(3)UDP信息包的标题很短,只有8个字节
(4)吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
(5)UDP使用尽最大努力交付,即不保证可靠交付
(6)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小
1.4. 多线程:
Java中创建线程有两种方法:使用Thread类和使用Runnable接口。在使用Runnable接口时需要建立一个Thread实例。因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例。
Java中关于线程调度的API最主要的有下面几个: 线程睡眠:(long millis)方法 线程等待:Object类中的wait()方法 线程让步:() 方法 线程加入:join()方法
线程唤醒:Object类中的notify()方法
2. 设计思路:
2.1. 线程设计:
(1)获取从服务其传送到的请求报文的数据,将原报文内的数据封装进一个新的DatagramPacket中。
(2)选取处于0-1500之间的随机数,作为睡眠时间。
(3)睡眠时间结束后,开始向获取到的客户端的地址和端口发送封装好的DatagramPacket
2.2. 服务器设计:
(1)定义一个UDP的DatagramSocket传送数据,记录服务器启动的时间
(2)进入死循环,不断监听是否有客户端传送来的请求报文,若有,转(3)
(3)计算当前时间与服务器启动时间的差值,若差值处于5秒到秒之间,返回(2)(模拟分组丢失);否则启动新线程
2.3. 客户端设计:
(1)定义一个UDP的DatagramSocket传送数据。
(2)将关键字PingUDP,序号和时间戳封装到DatagramPacket中作为报文的内容。
(3)向服务器的制定端口发送封装好的报文信息 (4)设置超时计时器
(5)超过超时计时器的时间未收到服务器发来的响应报文,则返回(2);否则,转(5)
(6)判断接收到的报文是否与当前发送的报文相对应,若是,返回(2);否则,返回(5)。
3. 程序流程图:
3.1. Java线程程序流程图:
启动线程延迟一段随机时间根据获取到的地址和端口,将原报文回送给客户端结束线程 3.2. PingServer程序流程图:
启动服务器等待客户端连接获取客户端发来的消息分组接收时间是否处于5秒到5.5秒之间模拟分组丢失启动线程,可以并发处理多个请求关闭服务器?NY关闭服务器
3.3. PingClient程序流程图:
启动客户机发送报文Y1秒内有没有收到回送报文?NY报文是否对应当前报文?N发送失败丢弃该报文发送成功发送次数加1发送次数>10?NY发送完成
4. 代码:
4.1. 线程代码:
/** * */
import * 线程
* @author LingHuacai * */
public class ThreadServer extends Thread{ private DatagramSocket socket; private DatagramPacket packet;
public ThreadServer(DatagramSocket socket, DatagramPacket packet){
/** * 服务器端
* @author LingHuacai * */
public class PingServer extends Thread{ //监听的端口号
private int initPort;
private byte[] buf = new byte[32]; private DatagramPacket packet; private DatagramSocket socket; public PingServer(int initPort){ = initPort; }
public void run(){ try{ //初始化socket,定义socket的端口号 socket = new DatagramSocket(initPort); \"Server started\"); }catch(SocketException e){ \"监听端口\"+initPort+\"失败\"); (); //初始化端口号失败,终止程序 (0); } //记录当前时间 long startTime = (); //死循环,不断监听是否有报文请求 while(true){ try {
packet = new DatagramPacket(buf,; //获取客户端发来的报文 (packet);
}catch(IOException e){ (); }
//输出分组和服务器启动时间的差值
\"接收到这个分组的的时间与服务器启动时间差:\"+()-startTime)+\"毫秒!\"); if(5000>()-startTime) || ()-startTime)>5500){ ThreadServer server = new ThreadServer(socket, packet);
//启动线程 (); } }
else \"报文丢失!\");
}
public void destroy(){ (); }
public static void main(String[] args){ //初始化服务器 PingServer ping = new PingServer(args[0])); (); } }
4.2. 客户端代码:
import * 客户端
* @author LingHuacai * */
public class PingClient extends Thread { private DatagramSocket client; private InetAddress hostAddress;
int port;
//定义并初始化接收到的响应报文的个数 int j = 0;
//定义并初始化最小往返时间,最大往返时间,平均往返时间 long minRtt=0, maxRtt=0, avrRtt=0, sumRtt=0; long[] rtt = new long[10];
public PingClient(String host,int port){ = port; try { client = new DatagramSocket(); //获取客户端地址 hostAddress = (host); } catch (UnknownHostException e) { // TODO Auto-generated catch block (); }catch(SocketException ee){ (); } }
public void run(){ //定义时间戳格式 SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-ddhh:mm:\"); for(int i=0; i<10; i++){ rtt[i] = 0; } for(int i = 0;i<10;i++){ //发送报文中的时间 Date sendTime = new Date(); String outMessage = new String(\"PingUDP:\"+i+\
String recieve = null; byte[] buffer = (); byte[] buf = new byte[]; DatagramPacket sendPacket = new DatagramPacket(buffer, , hostAddress, port);
DatagramPacket recievePacket = new DatagramPacket(buf, ;
try { (sendPacket); //设置超时时间为1秒 (1000);
收报文
//接收响应报文 (recievePacket);
recieve = new String());
//判断是否为延时报文,若为延时报文则丢弃,继续接
while(!(outMessage)){ recieve = null; (recievePacket); recieve = new String()); } //记录接收后时间 Date recieveTime = new Date(); //计算往返时间 rtt[i] = ()(); } catch (IOException e) { // TODO Auto-generated catch block \"响应报文丢失或超时!\"+\"\\n\"); (); } if(recieve!=null){ \"rtt:\"+rtt[i]); } }
if(rtt[0]!=0){ minRtt = rtt[0]; maxRtt = rtt[0]; sumRtt = rtt[0]; j++; }
else minRtt = 2000;
for(int i=1; i<10; i++){ if(rtt[i]!=0){ j++; //计算最小往返时间 if(minRtt>rtt[i]){ minRtt = rtt[i]; } //最大往返时间 if(maxRtt } //总往返时间 sumRtt = sumRtt + rtt[i]; } } if(j!=0){ //计算平均往返时间 avrRtt = sumRtt/j; \"共发送10个请求,成功接收\"+j+\"回复报文\"); \"最小往返时间为:\"+minRtt); \"最大往返时间为:\"+maxRtt); \"平均往返时间为:\"+avrRtt); } else{ \"发送请求失败!无回送报文\"); } //关闭线程 (); public static void main(String[] args){ PingClient clientThread = new PingClient(args[0], (args[1])); (); } } 5. 编译过程与截图 将文件和文件添加到指定目录中 使用cmd命令(注:使用的计算机需安装了java的JDK并且能够使用cmd来编译Java程序)编译运行文件和文件过程如下: (1)输入文件所在的硬盘,如:C: (2)使用\"cd 文件夹名\"来打开文件所在的文件夹,如果文件直接存在硬盘之下,则转(3);如果文件的文件夹在另一个文件夹中,则多次输入\"cd 文件夹名\"直到到达文件所在的目录 (3)分别使用cmd来编译文件,cmd命令如下: javac javac (4)编译成功后,先使用\"java PingServer 端口号\"(端口号是任意的,类型为整型)命令来运行服务器端;再使用\"java PingClient 地址 端口号\"(地址使用本机地址,即:;端口号要与服务器端口号相同)运行客户端。 服务器端运行截图: 客户端运行截图: 6. 课程设计小结 我选择了编程实现基于UDP的PING作为这次的计算机网络课程设计的题目。原本是打算写链路状态路由算法,看了书上的内容也找了一些资料,可是弄不太懂路由器之间的初始路由表是怎么获得的,于是就选了这个主题,比较明白易懂一点。但是由于之前没有接触过网络的编程,并不了解网络Socket的使用,所以在编程的时候碰到一些瓶颈。 在设计客户端最多等待1秒接收服务器端返回的信息用的时间最久,本来想是不是应该在PingClient端使用wait()方法来停止时间,使用另一个线程来进行接收服务器端回送的数据,后来想到还有1秒钟这个限制。想过很多种方 法,也尝试过很多方法,一边学习一边编程,了解到DatagramSocket的receive方法是阻塞模式的,原本并不知道阻塞模式是什么。后来才在网上看到DatagramSocket有SetSoTimeout这个方法可以在一段时间之后抛出一个异常来终止receive的阻塞模式。 通过这次的课程设计,我了解了一点有关网络编程的基本知识,对ICMP有了更深刻的了解。 因篇幅问题不能全部显示,请点此查看更多更全内容