⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sendwindow.java

📁 本程序可在局域网内实现聊天、传送文件功能
💻 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 + -