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

📄 comchannel.java

📁 这是一个虚拟网络模拟器
💻 JAVA
字号:
//: ComChannel.java
//: 模拟实现全双工通信信道
//package classes;
import java.io.*;
import java.awt.*;
import java.util.*;
import javax.swing.*;

class ComChannel
{
	private boolean isUsable;					// 该信道是否可用的标志
	private PipedOutputStream  dataIn;			// 数据传输信道输入端
	private PipedInputStream   dataOut;			// 数据传输信道输出端
	private ObjectOutputStream dataWrite;		// 负责将帧写入数据传输信道
	private ObjectInputStream  dataRead;		// 负责将帧读出数据传输信道

	private ACKChannel ackChannel;				// 负责确认帧得传输
	private ChannelPanel panel;					// 演示面板
	private int dataNum;						// 通过管道的数据帧的数目
	
	ComChannel(ChannelPanel panel)
	{
		this.panel = panel;						// 参数传递
		
		try
		{
			ackChannel= new ACKChannel();
			isUsable  = true;
			dataNum   = 0;
			dataIn    = new PipedOutputStream();
			dataOut   = new PipedInputStream(dataIn);
			dataWrite = new ObjectOutputStream(dataIn);
			dataRead  = new ObjectInputStream(dataOut);
		}
		catch(Exception e)
		{
			isUsable = false;
			e.printStackTrace();
		}	
	}
	
	// 判断该信道是否可用
	public boolean isUsable()
	{
		if(ackChannel.isUsable()==false)
		{
			return false;
		}
		return isUsable;
	}
	
	// 开始通信
	public void start()
	{
		dataNum   = 0;
		ackChannel.start();				// 通知确认帧接收信道
		panel.start();					// 通知演示面板
	}
	
	// 关闭该信道,关闭成功返回true,否则返回false
	public boolean close()
	{
		try
		{
			if(ackChannel.close()==false)
			{
				return false;
			}
			dataIn.close();
			dataOut.close();
			dataWrite.close();
			dataRead.close();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return false;
		}
		return true;	
	}
	
	// 将数据放入信道,若成功返回true,否则返回false
	synchronized public boolean pushData(DataFrame frame)
	{
		//System.out.println("pushData()");//!!!!!!!!!!!!!!!!!!!!!!!!!!
		try
		{
			dataWrite.writeObject(frame);
			dataWrite.flush();
			panel.push(frame);				// 通知演示面板
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	// 将确认放入信道,若成功返回true,否则返回false
	public boolean pushAck(DataFrame frame)
	{
		if(ackChannel.pushAck(frame)==false)
		{
			return false;
		}
		return true;
	}
	
	// 从信道中取出数据,若读取失败返回null
	public DataFrame popData()
	{
		DataFrame frame = null;
		try
		{
			//System.out.println("dataNum="+dataNum);//!!!!!!
			
			if(dataNum%32==26)	// 制造超时
			{
				frame = (DataFrame)dataRead.readObject();
				panel.pop(frame);				// 通知演示面板	
				dataNum++;
			}
			
			frame = (DataFrame)dataRead.readObject();
			//System.out.println("popData()()"+"frame="+frame.getSeq());//!!!!!!!!!!!!!!!!!!!!!!!!!!
			panel.pop(frame);				// 通知演示面板	
			dataNum++;
			if(dataNum%32==10)	// 制造错误帧
			{
				System.out.println("dataNum="+dataNum);//!!!!!!!
				System.out.println("错误帧frame="+frame.getSeq());//!!!!!!!
				frame.setCheckSum(false);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
		synchronized(this)
		{
			//System.out.println("popData()return");//!!!!!!!!!!!!!!!!!!!!!!!!!!
			return frame;
		}
	}
	
	// 从信道中取出确认,若读取失败返回null
	public DataFrame popAck()
	{
		DataFrame frame = null;
		frame = ackChannel.popAck();
		return frame;
	}
	
	// 负责确认的传输
	class ACKChannel
	{
		private boolean isUsable;				// 该信道是否可用的标志
		private PipedOutputStream  in;			// 确认传输信道输入端
		private PipedInputStream   out;			// 确认传输信道输出端
		private ObjectOutputStream write;		// 负责将帧写入确认传输信道
		private ObjectInputStream  read;		// 负责将帧读出确认传输信道
		private int ackNum;						// 通过管道的确认帧的数目
		
		ACKChannel()
		{
			try
			{
				isUsable  = true;
				ackNum = 0;
				in     = new PipedOutputStream();
				out    = new PipedInputStream(in);
				write  = new ObjectOutputStream(in);
				read   = new ObjectInputStream(out);
			}
			catch(Exception e)
			{
				isUsable = false;
				e.printStackTrace();
			}	
		}
		
		// 判断该信道是否可用
		public boolean isUsable()
		{
			return isUsable;
		}
		
		// 开始通信
		public void start()
		{
			ackNum   = 0;
		}
	
		// 关闭该信道,关闭成功返回true,否则返回false
		public boolean close()
		{
			try
			{
				in.close();
				out.close();
				write.close();
				read.close();
			}
			catch(IOException e)
			{
				e.printStackTrace();
				return false;
			}
			return true;	
		}
		
		// 将确认放入信道,若成功返回true,否则返回false
		synchronized public boolean pushAck(DataFrame frame)
		{
			try
			{
				write.writeObject(frame);
				write.flush();
				panel.push(frame);				// 通知演示面板
			}
			catch(IOException e)
			{
				e.printStackTrace();
				return false;
			}	
			return true;
		}
		
		// 从信道中取出确认,若读取失败返回null
		public DataFrame popAck()
		{
			DataFrame frame = null;
			try
			{
				
				if(ackNum%32==10)	// 制造超时
				{
					frame = (DataFrame)read.readObject();
					ackNum++;
				}
				
				frame = (DataFrame)read.readObject();
				//System.out.println(frame.getAck());
				synchronized(this)
				{
					ackNum++;
					/*
					if(ackNum%32==26)	// 制造错误帧
					{
						frame.setCheckSum(false);
					}
					*/
					panel.pop(frame);				// 通知演示面板	
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
				return null;
			}
			return frame;
		}
	}
}

class ChannelPanel extends JPanel
{
	private int width;				// 面板的大小
	private int height;
	private Color backColor;		// 背景颜色
	
	private LinkedList dataList;	// 管道中存在的数据帧
	private LinkedList ackList;		// 管道中存在的确认帧

	ChannelPanel(int width, int height)
	{
		this.width  = width;		// 参数传递
		this.height = height;
		
		backColor   = Color.white;	// 变量初始化
		dataList    = new LinkedList();
		ackList     = new LinkedList();
	}
	
	// 停止演示
	public void start()
	{
		if(!(dataList.isEmpty()))
		{
			dataList.clear();
		}
		if(!(ackList.isEmpty()))
		{
			ackList.clear();
		}
		this.repaint();
	}
	
	// 将帧frame压入管道
	synchronized public void push(DataFrame frame)
	{
		//System.out.println("kind = "+frame.getKind());//!!!!!!
		if(frame.getKind()==DataFrame.DATA)
		{
			dataList.addFirst(frame);
		}
		else
		{
			ackList.addFirst(frame);
		}
		//System.out.println("kind = "+frame.getKind()+"datalist.size = "+dataList.size());//!!!!!!
		this.repaint();
	}
	
	// 将帧frame弹出管道
	synchronized public void pop(DataFrame frame)
	{
		if(frame.getKind()==DataFrame.DATA)
		{
			if(!(dataList.isEmpty()))
			{
				//System.out.println(" dataList.removeLast();");//!!!!!!
				dataList.removeLast();
			}
			//System.out.println("pop(DataFrame frame)repaint();");//!!!!!!
		}
		else
		{
			if(!(ackList.isEmpty()))
			{
				ackList.removeLast();
			}
		}
		
		this.repaint();
	}
	
	// 绘制以(x0,y0)为中心的管道,宽为width,高为height
	private void pipeline(int x0, int y0, int width, int height, Graphics g)
	{
		int ellipseH = height;					// 椭圆的大小
		int ellipseW = ellipseH/2;
		
		int ellipseLX = x0 - width/2;			// 左椭圆外接矩形左上角坐标
		int ellipseLY = y0 - height/2;
		//g.fillOval(ellipseLX,ellipseLY,ellipseW,ellipseH);	// 左椭圆
		
		int ellipseRX = x0+width/2-ellipseW;	// 右椭圆外接矩形左上角坐标
		int ellipseRY = y0 - height/2;
		//g.fillOval(ellipseRX,ellipseRY,ellipseW,ellipseH);	// 右椭圆
		
		int lux = ellipseLX + ellipseW/2;		// 上横线左坐标
		int luy = ellipseLY;
		int rux = ellipseRX + ellipseW/2;		// 上横线右坐标
		int ruy = luy;
		//g.drawLine(lux,luy,rux,ruy);			// 上横
		
		int llx = lux;							// 下横线左坐标
		int lly = luy + height;
		int rlx = rux;							// 下横线右坐标
		int rly = lly;
		//g.drawLine(llx,lly,rlx,rly);			// 下横
		
		g.setColor(Color.gray);					// 设置颜色
		g.fillRect(0, ellipseLY, rlx+45, rly-10);
		int arrowW  = 4;						// 箭头宽度
		
		// 绘制确认帧出管道方向指示,与发送方面板有衔接
		int ackArrowX0 = lux;					// 箭头尾部中心坐标
		int ackArrowY0 = y0 - height/4;
		int exitLX  = 0;						// 与发送方衔接参数
		int exitLY  = ackArrowY0 - 3;
		g.drawLine(ackArrowX0,ackArrowY0-arrowW/2,0,exitLY-arrowW/2);
		g.drawLine(ackArrowX0,ackArrowY0+arrowW/2,0,exitLY+arrowW/2);
		
		// 绘制数据帧出管道方向指示,与接收方面板有衔接
		int dataArrowX0 = rux;					// 箭头尾部中心坐标
		int dataArrowY0 = y0 + height/4;
		int exitRX  = 0;						// 与接收方衔接参数
		int exitRY  = dataArrowY0 + 16;
		g.drawLine(dataArrowX0,dataArrowY0-arrowW/2,this.width,exitRY-arrowW/2);
		g.drawLine(dataArrowX0,dataArrowY0+arrowW/2,this.width,exitRY+arrowW/2);
	}
	
	// 以mid为纵坐标,在start和end之间绘出管道中存在的数据帧
	private void paintData(int start, int end, int mid, Graphics g)
	{
		//int size = 7;
		int size = dataList.size();
		if(size>0)
		{
			int len = end - start;		// 总长度
			int w   = 33;				// 帧的大小
			int h   = 15;
			int lx   = start;			// 帧左上角的X坐标
			int ly   = mid - h/2;		// 帧左上角的Y坐标
			int dis	= len/size;			// 两帧起点之间的间隔
			//System.out.println("paintData!!!!!!!!");
			for(int i=0;i<size;i++)
			{
				//System.out.println("frameX0="+lx+" size="+size);
				DataFrame frame = (DataFrame)dataList.get(i);
				int seq = frame.getSeq();
				g.drawRect(lx,ly,w,h);
				g.drawString("data"+seq,lx+2,ly+h-3);
				g.drawLine(lx+w,mid,lx+w+12,mid);
				g.drawLine(lx+w+12,mid,lx+w+7,mid-3);
				g.drawLine(lx+w+12,mid,lx+w+7,mid+3);
				lx = lx + dis;
			}
		}
	}
	
	// 以mid为纵坐标,在start和end之间绘出管道中存在的确认帧
	private void paintACK(int start, int end, int mid, Graphics g)
	{
		//int size = 7;
		int size = ackList.size();
		if(size>0)
		{
			int len = start - end;		// 总长度
			int w   = 33;				// 帧的大小
			int h   = 15;
			int lx   = start;			// 帧右上角的X坐标
			int ly   = mid - h/2;		// 帧右上角的Y坐标
			int dis	= len/size;			// 两帧起点之间的间隔
			for(int i=0;i<size;i++)
			{
				//System.out.println("frameX0="+lx+" size="+size);
				DataFrame frame = (DataFrame)ackList.get(i);
				int seq = frame.getAck();
				g.drawRect(lx-w,ly,w,h);
				//g.drawString("ACK"+7,lx-w+2,ly+h-3);
				g.drawString("ACK"+seq,lx-w+2,ly+h-3);
				g.drawLine(lx-w,mid,lx-w-12,mid);
				g.drawLine(lx-w-12,mid,lx-w-7,mid-3);
				g.drawLine(lx-w-12,mid,lx-w-7,mid+3);
				lx = lx - dis;
			}
		}
	}
	
	synchronized public void paintComponent(Graphics g)
	{
		super.paintComponent(g);	
		
		g.setColor(backColor);							// 清屏
		g.fillRect(0,0,width,height);
		
		g.setColor(Color.black);
		//g.drawLine(1,5,20,5);							// 上横
		//g.drawLine(1,5,width-1,5);
		//g.drawLine(1,5,1,height-5);						// 左竖
		//g.drawLine(1,height-5,width-1,height-5);		// 下横
		//g.drawLine(width-1,5,width-1,height-5);			// 右竖
		g.drawString("通信信道",100,20);					// 标题
		//g.setColor(Color.red);
		//g.fillRect(1,5 , 20, 5);
		int x0 = width/2;								// 管道中心
		int y0 = height/3;
		int pipWidth = width - 20;						// 管道大小
		int pipHeight= height/3;
		pipeline(x0,y0,pipWidth,pipHeight,g);			// 绘制管道
		paintData(0,width-pipHeight/2,y0+pipHeight/4,g);// 绘制数据帧
		paintACK(width,0+pipHeight/2,y0-pipHeight/4,g);	// 绘制确认帧
  	}
}///:~

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -