数学模型第四版答案:谁能用C或VB写网络的连续重传协议?

来源:百度文库 编辑:杭州交通信息网 时间:2024/05/09 19:35:12
如题

A协议

我们约定:请求上传的主机叫为A,作出响应的主机叫为B。现在A要上传文件给B:

(1) A主动去PING(发送类型为PING的包) B,若失败(超时),则报告“对方主机不在线”而退出;否则,转到(2)。

(2) A主动发送写请求给B,若失败(超时),则报告错误而退出;否则记下目的文件当前大小,并转到(3)。

(3) A打开源文件(且定位到要开始传送的位置)并载入数据到缓存中。

(4) 从缓存中循环发送窗口大小个的数据包;若收到OVER(指的是REC_ALL 或 ABORT),则立即退出;若超过循环次数,则报告超时错误而退出。

(5) 收到ACK+块号时,设置块号(若块号为0,则载入数据到缓存)并重置循环次数。

(6) 收到ABORT 或 REC_ALL,则退出。

相关说明:

(1) 每次从源文件中载入数据都要记下载入长度,以便控制文件结尾的数据包大小。

(2) ACK 中块号标志“需要收到的包”。

(3) 由于协议(5)不断修改块号和重置循环次数,从而协议(4)的窗口不断移动。

(4) 到了缓存末端,可能循环发送小于窗口大小个的数据包。

(5) 写请求包中含有文件名,文件大小,数据内容大小。

B协议

(1) 若收到PING,则立即发送PING_OK。

(2) 若收到WRITE,则记下文件标号.文件名.文件大小.数据内容大小,并做好接收数据准备(打开或新建文件),并发送WRITE_OK 。

(3) 若收到TRANSFER,则重置计数器,检查长度是否正确,再检查是不是当前要的包,若是则写入文件中且块号加一,接着检查文件数据是否接收完毕,若完毕则发送REC_ALL并退出,否则发送ACK+块号。

相关说明:

(1) WRITE_OK 中载有目的文件的当前大小,这样可以做到续传。

(2) 若计数器到时,则报告超时且发送ABORT而退出。

实现

以下给出部分协议实现代码:
(1)A端

打开和关闭流#region 打开和关闭流

private void Open()
{
if(MyStream==null)
{
if(File.Exists(this.FileName))
{
MyStream=new FileStream(this.FileName,FileMode.Open,FileAccess.Read,FileShare.Read);
MyStream.Seek(_Position,SeekOrigin.Begin);
}
else throw new Exception(this.FileName+" 不存在!");
}
}

public void Close()
{
if(MyStream!=null)
{
MyStream.Close();
MyStream=null;
}
}

#endregion

public void HandleWRITE_OK(UFTP_Packet packet)
{
if(!WRITE_OK)
{
this.WRITE_OK=true;
this._Position=Convert.ToInt64(System.Text.Encoding.Unicode.GetString(packet.MessageBuffer));
}
}

public void HandleACK(UFTP_Packet packet)
{
if(packet.AliceID==0 && this._AliceID>0)
{
LoadData();

}
this._AliceID=packet.AliceID;
this._Time=1000;
}

/**//// <summary>
/// 把文件数据发出去
/// </summary>
private void SendThread()
{
if(!this.Ping() ||!this.SendWRITE())
{
ShowError("Ping or Write Fail");
this.Dispose();
return;
}
//
Open();
LoadData();
//
UFTP_Packet packet=new UFTP_Packet();
packet.FileID=this.FileID;
packet.UFTPType=UFTP_Packet.UFTPEnum.TRANSFER;
while(_Time>0)
{
uint start=(ushort)(_AliceID*Multi.UnitSize);
uint file_end=_FileEnd;
for(uint i=start;i<start+WindowSize*Multi.UnitSize && i<file_end;i+=Multi.UnitSize)
{
if(OVER)return;
packet.AliceID=(ushort)(i/Multi.UnitSize);
uint len=Math.Min(Multi.UnitSize,file_end-i);
if(len<=0)break;
packet.MessageBuffer=new byte[len];
Array.Copy(this.Buffe,i,packet.MessageBuffer,0,len);
SendPacket(packet.ToBytes());
Thread.Sleep(1);
}
_Time--;
}
if(!OVER)
{
ShowError("对方主机失去响应,超时退出");
}
//
this.Dispose();
}

/**//// <summary>
/// 从源文件中载入数据
/// </summary>
private void LoadData()
{
this._FileEnd=(uint)MyStream.Read(this.Buffe,0,this.Buffe.Length);
}

/**//// <summary>
/// 发送PING
/// </summary>
/// <returns></returns>
private bool Ping()
{
UFTP_Packet ping=new UFTP_Packet();
ping.FileID=this.FileID;
ping.UFTPType=UFTP_Packet.UFTPEnum.PING;
for(int i=0;i<10;i++)
{
SendPacket(ping.ToBytes());
Thread.Sleep(100);
if(this.PING_OK)return true;
}
return false;
}

/**//// <summary>
/// 发送写操作
/// </summary>
/// <returns></returns>
private bool SendWRITE()
{
FileInfo info=new FileInfo(FileName);
UFTP_Packet packet=new UFTP_Packet();
packet.FileID=this.FileID;
ushort len=(ushort)(this.Buffe.Length/Multi.UnitSize);
byte[] write=packet.ToBytes(UFTP_Packet.UFTPEnum.WRITE,
System.Text.Encoding.Unicode.GetBytes(info.Name+"|"+info.Length.ToString()+"|"+len.ToString()));
for(int i=0;i<10;i++)
{
SendPacket(write);
Thread.Sleep(100);
if(this.WRITE_OK)return true;
}
return false;
}

/**//// <summary>
/// 创建文件标志号
/// </summary>
/// <returns></returns>
private ushort CreateFileId()
{
return (ushort)(new System.Random().Next()%ushort.MaxValue);
}

(2)B端

public void HandleWRITE()
{
if(MyStream==null)
{
try
{
MyStream=new FileStream(SavePath+@"\"+FileName,FileMode.Append,FileAccess.Write,FileShare.Read);
_Count=_Position=MyStream.Position;
SendWRITE_OK();
}
catch(Exception ex)
{
this.Dispose(ex.Message);
}
}
}

public void SendWRITE_OK()
{
if(MyStream!=null)
{
_UFTP.FileID=this.FileId;
_UFTP.AliceID=this.AliceId;
_UFTP.UFTPType=UFTP_Packet.UFTPEnum.WRITE_OK;
_UFTP.MessageBuffer=System.Text.Encoding.Unicode.GetBytes(_Position.ToString());
SendPacket(_UFTP.ToBytes());
}
}

处理传输#region 处理传输

public void HandleTRANSFER(UFTP_Packet packet)
{
if(packet.MessageLength!=Multi.UnitSize && packet.MessageLength!=(FileLen%Multi.UnitSize))return;
//
_IsTimeOut=false;
//
if(packet.AliceID==this.AliceId)
{
WriteData(packet.MessageBuffer);
this.AliceId=(ushort)((this.AliceId+1)%this.BuffeLen);
}
//
if(this._Count<FileLen)
{
SendAck();
}
else if(this._Count==FileLen)
{
Console.WriteLine("=");
Close();
}
else if(this._Count>FileLen)
{
Console.WriteLine(">");
Close();
}

}

private void SendAck()
{
_UFTP.FileID=this.FileId;
_UFTP.AliceID=this.AliceId;
_UFTP.UFTPType=UFTP_Packet.UFTPEnum.ACK;
SendPacket(_UFTP.ToBytes());
}

private void WriteData(byte[] data)
{
if(MyStream!=null)
{
MyStream.Write(data,0,data.Length);
this._Count+=data.Length;
}
}

private void Close()
{
//告诉对方文件传输完毕
_UFTP.FileID=this.FileId;
_UFTP.AliceID=this.AliceId;
_UFTP.UFTPType=UFTP_Packet.UFTPEnum.REC_ALL;
for(int i=0;i<3;i++)SendPacket(_UFTP.ToBytes());
//
this.Dispose();
}

#endregion
总结

改进TFTP,主要是在传输机制上(TFTP是用的是停止等待,而UFTP用的是连续重传),这样传输吞吐率有了提高。

UFTP调试成功,运行的结果还较理想。但它还有很多不足,它只实现了上传,没有下载。

大哥,写一个协议太复杂了吧

不能