1. 编写接收端代码
接收端模拟网络环境较差时情况,每次生成一个随机数,小于0.8时不丢包,大于0.8时丢包。
接收数据格式:编号+空格+内容
返回数据格式:
丢包:Loss+空格+编号
未丢包:ACK+空格+编号
接收包非累计计数时不做处理。
2. 编写发送端代码
发送端较为复杂,分为两个线程:
发送线程:
设置窗口大小为5,当超过窗口时死循环,停止发送;
处理线程:
判断是否ACK,如果累计增加,窗口向右滑动一格,否则重发;
另设置20个定时器,如果超过5秒未响应,则重发。
理论上来说5个定时器就够了,但懒得改了(
Receiver代码:
import java.net.*; public class Receiver { public static int send_port = 8899; public static int receive_port = 8848; public static void main(String[] args) throws Exception { InetAddress serverAddress = InetAddress.getByName("localhost"); DatagramSocket socket = new DatagramSocket(receive_port); int cnt=0; while (true){ byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, data.length); //此方法为阻塞方法 socket.receive(packet); String r = new String(packet.getData(),0, packet.getLength()); String[] result = r.split(" ",2); int num=Integer.parseInt(result[0]); if(Math.random()<0.8){ //ack if(num==cnt){ String str = "ACK "+cnt; byte[] res = str.getBytes(); DatagramPacket resp = new DatagramPacket(res, res.length, serverAddress, send_port); socket.send(resp); System.out.println("receive result : " + result[1]); cnt++; } else{ System.out.println("Discard packet "+num); } } else{ //loss String str = "Loss "+num; byte[] res = str.getBytes(); DatagramPacket resp = new DatagramPacket(res, res.length, serverAddress, send_port); socket.send(resp); System.out.println("Loss : "+num); } } } }View Code
Client代码:
import javax.swing.Timer; import java.io.IOException; import java.net.*; class Sender { //assume that the length of window is 5 public static volatile int l=0; public static volatile int r=4; public static volatile int current=0; public static DatagramSocket socket; public static InetAddress serverAddress; public static int receive_port = 8848; public static Timer[] timers; public static String[] str; Sender(DatagramSocket s,InetAddress in){ socket=s; serverAddress=in; str = new String[20]; for(int i=0;i<20;i++){ str[i]=i+" "+"Here is packet"+i; } timers = new Timer[20]; for(int i=0;i<str.length;i++){ int finalI = i; timers[i] = new Timer(5000, e -> { send(str[finalI]); System.out.println("Resend packet "+finalI); timers[finalI].restart(); }); } } public static void send(String s) { try { byte[] data = s.getBytes(); DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, receive_port); socket.send(packet); } catch (Exception e){ System.out.println(e.getMessage()); } } class SendPackage implements Runnable { @Override public void run(){ for(int i=0;i<str.length;i++){ send(str[i]); timers[i].start(); current=i; while(current==r); } } } class DealMessage implements Runnable{ @Override public void run() { while(l<str.length){ byte[] rec = new byte[1024]; DatagramPacket recp = new DatagramPacket(rec, rec.length); //此方法为阻塞方法 try { socket.receive(recp); } catch (IOException e) { throw new RuntimeException(e); } String res = new String(recp.getData(),0, recp.getLength()); System.out.println(res); String[] result=res.split(" ",2); int num=Integer.parseInt(result[1]); if(result[0].equals("ACK")){ if(num==l){ timers[num].stop(); l++; System.out.println("Packet "+num+" has been received."); r++; } } else if(result[0].equals("Loss")){ System.out.println("Loss!Ready to send packet "+num+" again."); } } } } } public class Client { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(8899); InetAddress serverAddress = InetAddress.getByName("localhost"); Sender sender = new Sender(socket,serverAddress); Sender.DealMessage dealMessage = sender.new DealMessage(); Thread t1=new Thread(dealMessage); t1.start(); Sender.SendPackage sendPackage = sender.new SendPackage(); Thread t2=new Thread(sendPackage); t2.start(); } }View Code
标签:String,int,Back,packet,static,new,Go,数据传输,public From: https://www.cnblogs.com/capterlliar/p/17353752.html