一、所实现停等协议简介
我设计的程序实现的是rdt3.0版本的停等协议,发送端将数据包以0、1交替的顺序发送数据包,当发送0数据包之后开始计时,只有接收到ack0才能继续发送1数据包,如果在没有接收到ack0的时候已经超时,这时候需要重传数据包0;
接收方按照所收到的数据包的编号返回相应的ack,当上一个收到的是数据包0后下一个只有是数据包1才能接收放到接收文件中,如果下一个还是数据包0那么就要丢弃。
二、分组格式
数据报格式:
三、UDP编程的特点
UDP协议是无连接的数据传输格式,所以就不用像tcp一样建立专门的socket连接特定的主机在传输数据,而是将每个数据包打包后将目的主机的host和端口号添加到数据包中之后就发送出去,而不提供任何的保持连接。
所以使用UDP编程就是以包的形式在DatagramSocket中传送和接受,在java中数包可以用datagramPacket()加上指定的host和端口而构成,之后就由datagramSocket()发送出去就行,相应的接收也是在以监听某接口的datagramSocket(****)接收包,在按照自己定义的数据包的格式提取出不同部分的有用信息即可。
四、实验实现的主要类及其作用
主要类:
server()类:实现服务器功能,接受数据包,解析后将有效信息输出到接收文件,返回相应数据包的ACK;
Client()类:实现客户端功能,从发送文件中读取信息,按照数据报的定义组合成一个个的数据报,向服务器发送数据包同时计时,并且控制超时、返回ack不是想要的等各种情况的相应处理。
实验中服务器和客户端都是以线程的形式启动,其接受和发送数据包在各自的run()方法中实现。
五、实验验证结果
模拟丢失ACK,会有超时重传:
数据传送完毕:read文件为发送的,receive为接收文件
package rdt; import java.net.*; import java.io.*; public class Server extends Thread{ public static final int MAX_LENGTH = 1024; public static DatagramSocket socket; public static int last; //上一次收到的包的编号 public static byte[] receive = new byte[MAX_LENGTH]; public static byte[] send = new byte[MAX_LENGTH]; public static OutputStream writeFile; public static InetAddress inetAddress; public static int port; public Server() { try { socket = new DatagramSocket(8888); last = 1; //因为第一个需要的是0号packet writeFile = new FileOutputStream("receive.txt"); receive[0] = 1; } catch (SocketException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } } public void run() { int timeOut = 0; //模拟最多超时的次数,之后恢复 while(true) { try{ DatagramPacket packet1 = new DatagramPacket(receive,receive.length); socket.receive(packet1); byte order = receive[0]; byte need = (byte)((last==0)?1:0); System.out.println("收到的数据包是:"+order+" 需要的是:"+need); //收到的是需要的数据包,则写入文件,回传ack if(need == order) { writeFile.write(receive, 1, packet1.getLength()-1); send[0] = need; last = order; System.out.println("回传的ack是:"+need); inetAddress = packet1.getAddress(); port = packet1.getPort(); System.out.println("主机名:"+inetAddress.getHostName()+" port:"+port); DatagramPacket packet2 = new DatagramPacket(send,send.length,inetAddress,port); if(timeOut++ > 1){ socket.send(packet2); } } else{ send[0] = order; System.out.println("传回来的包不是想要的,丢弃。。"); System.out.println("回传的ack是:"+need); inetAddress = packet1.getAddress(); port = packet1.getPort(); System.out.println("主机名:"+inetAddress.getHostName()+" port:"+port); DatagramPacket packet2 = new DatagramPacket(send,send.length,inetAddress,port); socket.send(packet2); } } catch (IOException e) { e.printStackTrace(); } } } }
package rdt; import java.net.*; import java.io.*; public class Client extends Thread{ public static int MAX_LENGTH = 1024; //每次读取文件的的最大字节数 public static final int TIMEOUT = 3000; //设置超时时间 public static byte[] receive = new byte[MAX_LENGTH]; public static DatagramSocket socket; public static InputStream inputFile = null; //从这读取传送数据 public static byte order; public static InetAddress inetAddress; public static int port; public Client () { try { socket = new DatagramSocket(); socket.setSoTimeout(TIMEOUT); inputFile = new FileInputStream("read.txt"); order = 0; //刚开始发送的是0数据包 inetAddress = InetAddress.getByName("localhost"); port = 8888; } catch (SocketException | FileNotFoundException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } } public void run() { int count = 0; //创建数据包 while(true) { int len; try { byte[] sendata = new byte[MAX_LENGTH]; sendata[0] = order; len = inputFile.read(sendata,1,sendata.length-1); count++; System.out.println(len); if(len == -1) //文件已经传送完毕 break; while(len != -1) { try{ DatagramPacket packet = new DatagramPacket(sendata,len,inetAddress,port); socket.send(packet); System.out.println("发送第"+count+"个数据报"); DatagramPacket packet2 = new DatagramPacket(receive,receive.length); socket.receive(packet2); byte ack = receive[0]; System.out.println("传出去的包是:"+order+"传回来的ACK是:"+ack); if(ack == order) { order = (byte) ((order==0)?1:0); break; //转到下一个转态 } //否则重传 }catch(SocketTimeoutException e) { //超时,需要重传 System.out.println("超时,重传"); } } } catch (IOException e) { e.printStackTrace(); } } } }