📄 sendwindow.java
字号:
package org.tuna.net.rdt;
import java.net.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.Timer;
/**
* 发送窗口
* 上层调用send()方法,将一段字节数组传递给sendwindow
* 若可以发送,则发送,并送入队列等待确认
* 否则通知上层拒绝发送
*
*/
class SendWindow implements DataSort
{
private RdtUnit rdtUnit;
private ArrayList<WaitingPacket> sendQueue;
private int next; //发送分组的下一个可用序号
private final int MAX_LEN = 30; //窗口最大尺寸
private int finalNumber = 29; //当前可发送的最大序号,超过此序号会使接收方溢出
private int timeout;
public SendWindow(RdtUnit ru)
{
rdtUnit = ru;
next = 0;
timeout = 30;
sendQueue = new ArrayList<WaitingPacket>();
}
public int length()
{
return sendQueue.size();
}
/**
* 将上层传递的字节数组打包送入队列中等待发送
*/
public boolean send(byte[] data) throws Exception
{
if ( !isSendable() ) return false;
RdtPacket rp = new RdtPacket((int)PKT_DATA, next++, data);
byte[] sendData = rp.getPostBytes();
DatagramPacket snd = new DatagramPacket(sendData, sendData.length, rdtUnit.addr, rdtUnit.port);
rdtUnit.sock.send(snd);
WaitingPacket waiting = new WaitingPacket(rp);
sendQueue.add(waiting); //进入队列等待确认
return true;
}
private boolean isSendable()
{
if ( isFull() ) return false; //发送窗口已满
if ( next > finalNumber )
return false;
else
return true;
}
/**
* 确认指定序号的分组
* 这里忽略其他的错误
* @param srpkt 已包装的确认分组
*/
public void ensure(RdtPacket srpkt)
{
byte[] msg = srpkt.getData();
if (msg == null) {return;}
else if (msg.length < 2) {return;}
if (msg[0] != (byte)1) {return;} //非ACK
int rcvSize = (int)msg[1]; //接收方的剩余容量,由于小于128,所以直接置于一个字节的空间中
int num = srpkt.getNum(); //准备确认的分组的序号
finalNumber = num + rcvSize; //计算出当前可发送的最大序号(可以大于可容纳的最大序号,当确认分组丢失时)
if (next - 1 > finalNumber) //如果下一个可用序号大于finalNumber,则修改next
next = finalNumber + 1;
//寻找相应分组进行确认
for(int i = 0; i < sendQueue.size(); i++)
if (sendQueue.get(i).getRdt().getNum() == num)
{
sendQueue.get(i).ensure();
break;
}
//从队首开始检查是否有可出队的分组(积累确认原则)
while(sendQueue.size() > 0 && sendQueue.get(0).isEnsured())
{
sendQueue.remove(0);
}
}
public boolean isFull()
{
return sendQueue.size() < MAX_LEN ? false : true;
}
public boolean isEmpty()
{
return sendQueue.size() == 0 ? true : false;
}
public void destroy()
{
while(sendQueue.size() > 0)
sendQueue.remove(0);
}
/*处于等待确认状态中的分组结构,封装了确认标志和定时器*/
private class WaitingPacket
{
private RdtPacket rdtpkt;
private boolean sure = false;
private javax.swing.Timer timeoutMonitor;
private Timer fuck;
private class TimeoutAction implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
try
{
byte[] data = rdtpkt.getPostBytes();
DatagramPacket sndpkt =
new DatagramPacket(data, data.length, SendWindow.this.rdtUnit.addr, SendWindow.this.rdtUnit.port);
SendWindow.this.rdtUnit.sock.send(sndpkt);
}
catch(Exception ex){
//ex.printStackTrace();
}
}
}
public WaitingPacket(RdtPacket rp)
{
rdtpkt = rp;
sure = false;
timeoutMonitor = new javax.swing.Timer(SendWindow.this.timeout, new TimeoutAction());
timeoutMonitor.start();
}
public void setTimeout()
{
timeoutMonitor.setDelay(SendWindow.this.timeout);
}
public RdtPacket getRdt()
{
return rdtpkt;
}
public void ensure()
{
sure = true;
timeoutMonitor.stop();
}
public boolean isEnsured()
{
return sure;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -