基于不可靠数据报的文件传输

目录:

引言

数据报格式

协议

实现

总结

 

引言

这个学期学习了一下<<计算机网络>>,在此把它的一个小部分应用一下。大家都知道在TCP/IP中的运输层,有两种协议,那就是TCP和UDP。它们的区别,大家一定很清楚了,TCP面向连接的数据报传输,而UDP是无连接的数据报传输,从而TCP可以提供可靠的传输(不会出现包丢失,包错位等等,当然这只是站在应用层角度来看,其实TCP提供了完善的重传机制),UDP则只是尽最大努力交付,它是不可靠的(也即可能出现包丢失,包的路由不同而错位等等),但它比TCP小巧快捷。

       FTP就是基于TCP的文件传输协议。但,最近我遇到了一种网络环境,它没有TCP,而只有UDP;现在,我们想通过这种网络环境实现文件传输。大家可能和我一样想到是用TFTP(基于UDP的文件传输协议),TFTP的包只有四种,实现起来也并不复杂,但是,它是基于停止等待协议,这种协议,数据传输的吞吐率太低。接着,我想到了把在数据链路层最实用的连续重传协议应用到文件传输中来。以下就来介始,我的实现过程。

 

数据报报头格式

       首先,我们把我们文件传输协议称为UFTP(Unlinked File Transfer Protocol),

接着我们来自定义UFTP的报头格式。

类型 文件标号
块号  检验和

 

以上,每个区都是16位。

1.类型:

public enum UFTPEnum :ushort

{

    WRITE=1,WRITE_OK=2,TRANSFER=3,ACK=4,REC_ALL=5,MSG=6,ERROR=7,PING=8,PING_OK=9 ,ABORT=10

}


MSG:聊天信息

PING: 检查对方主机是否在线

PING_OK: 在线确认包

WRITE:写请求(也即上传)

WRITE_OK: 表示同意上传

TRANSFER: 表示文件传输数据包

ACK: 确认包

REC_ALL: 表示收到了文件所有数据.

ERROR:表示错误包(如检验和不对的包)

ABORT: 请求立即中止

 

2.文件标号:

        唯一标志要传输的文件。

3.块号:

       唯一标志所传输的块.

4.检验和:

       用来检查包是否正确.

 

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端

ContractedBlock.gif ExpandedBlockStart.gif 打开和关闭流 #region 打开和关闭流 
InBlock.gif 
InBlock.gif        
private void Open() 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
InBlock.gif            
if(MyStream==null
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                
if(File.Exists(this.FileName)) 
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif
InBlock.gif                    MyStream
=new FileStream(this.FileName,FileMode.Open,FileAccess.Read,FileShare.Read); 
InBlock.gif                    MyStream.Seek(_Position,SeekOrigin.Begin); 
ExpandedSubBlockEnd.gif                }
 
InBlock.gif                
else throw new Exception(this.FileName+" 不存在!"); 
ExpandedSubBlockEnd.gif            }
 
ExpandedSubBlockEnd.gif        }
 
InBlock.gif 
InBlock.gif        
public void Close() 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
InBlock.gif            
if(MyStream!=null
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                MyStream.Close(); 
InBlock.gif                MyStream
=null
ExpandedSubBlockEnd.gif            }
 
ExpandedSubBlockEnd.gif        }
 
InBlock.gif 
ExpandedBlockEnd.gif        
#endregion
  
None.gif 
None.gif        
public   void  HandleWRITE_OK(UFTP_Packet packet) 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            
if(!WRITE_OK) 
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                
this.WRITE_OK=true
InBlock.gif                
this._Position=Convert.ToInt64(System.Text.Encoding.Unicode.GetString(packet.MessageBuffer)); 
ExpandedSubBlockEnd.gif            }
 
ExpandedBlockEnd.gif        }
 
None.gif 
None.gif        
public   void  HandleACK(UFTP_Packet packet) 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            
if(packet.AliceID==0 && this._AliceID>0
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                LoadData(); 
InBlock.gif             
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
this._AliceID=packet.AliceID;  
InBlock.gif            
this._Time=1000
ExpandedBlockEnd.gif        }
 
None.gif 
ExpandedBlockStart.gifContractedBlock.gif        
/**/ /// <summary> 
InBlock.gif        
/// 把文件数据发出去 
ExpandedBlockEnd.gif        
/// </summary> 

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

None.gif          private   void  LoadData() 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            
this._FileEnd=(uint)MyStream.Read(this.Buffe,0,this.Buffe.Length); 
ExpandedBlockEnd.gif        }
 
None.gif 
ExpandedBlockStart.gifContractedBlock.gif        
/**/ /// <summary> 
InBlock.gif        
/// 发送PING 
InBlock.gif        
/// </summary> 
ExpandedBlockEnd.gif        
/// <returns></returns> 

None.gif          private   bool  Ping() 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            UFTP_Packet ping
=new UFTP_Packet(); 
InBlock.gif            ping.FileID
=this.FileID; 
InBlock.gif            ping.UFTPType
=UFTP_Packet.UFTPEnum.PING; 
InBlock.gif            
for(int i=0;i<10;i++
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                SendPacket(ping.ToBytes()); 
InBlock.gif                Thread.Sleep(
100); 
InBlock.gif                
if(this.PING_OK)return true
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
return false
ExpandedBlockEnd.gif        }
 
None.gif 
ExpandedBlockStart.gifContractedBlock.gif        
/**/ /// <summary> 
InBlock.gif        
/// 发送写操作 
InBlock.gif        
/// </summary> 
ExpandedBlockEnd.gif        
/// <returns></returns> 

None.gif          private   bool  SendWRITE() 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            FileInfo info
=new FileInfo(FileName); 
InBlock.gif            UFTP_Packet packet
=new UFTP_Packet(); 
InBlock.gif            packet.FileID
=this.FileID; 
InBlock.gif            
ushort len=(ushort)(this.Buffe.Length/Multi.UnitSize); 
InBlock.gif            
byte[] write=packet.ToBytes(UFTP_Packet.UFTPEnum.WRITE, 
InBlock.gif                System.Text.Encoding.Unicode.GetBytes(info.Name
+"|"+info.Length.ToString()+"|"+len.ToString())); 
InBlock.gif            
for(int i=0;i<10;i++
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                SendPacket(write); 
InBlock.gif                Thread.Sleep(
100); 
InBlock.gif                
if(this.WRITE_OK)return true
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
return false
ExpandedBlockEnd.gif        }
 
None.gif 
ExpandedBlockStart.gifContractedBlock.gif        
/**/ /// <summary> 
InBlock.gif        
/// 创建文件标志号 
InBlock.gif        
/// </summary> 
ExpandedBlockEnd.gif        
/// <returns></returns> 

None.gif          private   ushort  CreateFileId() 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            
return (ushort)(new System.Random().Next()%ushort.MaxValue); 
ExpandedBlockEnd.gif        }
 
None.gif 


 

(2)B端


None.gif          public   void  HandleWRITE() 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            
if(MyStream==null
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                
try 
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif
InBlock.gif                    MyStream
=new FileStream(SavePath+@"\"+FileName,FileMode.Append,FileAccess.Write,FileShare.Read); 
InBlock.gif                    _Count
=_Position=MyStream.Position; 
InBlock.gif                    SendWRITE_OK(); 
ExpandedSubBlockEnd.gif                }
 
InBlock.gif                
catch(Exception ex) 
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif
InBlock.gif                    
this.Dispose(ex.Message); 
ExpandedSubBlockEnd.gif                }
 
ExpandedSubBlockEnd.gif            }
 
ExpandedBlockEnd.gif        }
 
None.gif  
None.gif        
public   void  SendWRITE_OK() 
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif
InBlock.gif            
if(MyStream!=null
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                _UFTP.FileID
=this.FileId; 
InBlock.gif                _UFTP.AliceID
=this.AliceId; 
InBlock.gif                _UFTP.UFTPType
=UFTP_Packet.UFTPEnum.WRITE_OK; 
InBlock.gif                _UFTP.MessageBuffer
=System.Text.Encoding.Unicode.GetBytes(_Position.ToString()); 
InBlock.gif                SendPacket(_UFTP.ToBytes()); 
ExpandedSubBlockEnd.gif            }
 
ExpandedBlockEnd.gif        }
 
None.gif  
ContractedBlock.gifExpandedBlockStart.gif        
处理传输 #region 处理传输 
InBlock.gif  
InBlock.gif         
InBlock.gif        
public void HandleTRANSFER(UFTP_Packet packet) 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
InBlock.gif            
if(packet.MessageLength!=Multi.UnitSize && packet.MessageLength!=(FileLen%Multi.UnitSize))return
InBlock.gif            
// 
InBlock.gif
            _IsTimeOut=false
InBlock.gif            
// 
InBlock.gif
            if(packet.AliceID==this.AliceId) 
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                WriteData(packet.MessageBuffer); 
InBlock.gif                
this.AliceId=(ushort)((this.AliceId+1)%this.BuffeLen); 
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
// 
InBlock.gif
            if(this._Count<FileLen) 
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                SendAck(); 
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
else if(this._Count==FileLen) 
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                Console.WriteLine(
"=");     
InBlock.gif                Close(); 
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
else if(this._Count>FileLen) 
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                Console.WriteLine(
">");     
InBlock.gif                Close(); 
ExpandedSubBlockEnd.gif            }
 
InBlock.gif  
ExpandedSubBlockEnd.gif        }
 
InBlock.gif  
InBlock.gif        
private void SendAck() 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
InBlock.gif            _UFTP.FileID
=this.FileId; 
InBlock.gif            _UFTP.AliceID
=this.AliceId; 
InBlock.gif            _UFTP.UFTPType
=UFTP_Packet.UFTPEnum.ACK; 
InBlock.gif            SendPacket(_UFTP.ToBytes()); 
ExpandedSubBlockEnd.gif        }
 
InBlock.gif  
InBlock.gif        
private void WriteData(byte[] data) 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
InBlock.gif            
if(MyStream!=null
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                MyStream.Write(data,
0,data.Length); 
InBlock.gif                
this._Count+=data.Length; 
ExpandedSubBlockEnd.gif            }
 
ExpandedSubBlockEnd.gif        }
 
InBlock.gif  
InBlock.gif        
private void Close() 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
InBlock.gif            
//告诉对方文件传输完毕 
InBlock.gif
            _UFTP.FileID=this.FileId; 
InBlock.gif            _UFTP.AliceID
=this.AliceId; 
InBlock.gif            _UFTP.UFTPType
=UFTP_Packet.UFTPEnum.REC_ALL; 
InBlock.gif            
for(int i=0;i<3;i++)SendPacket(_UFTP.ToBytes()); 
InBlock.gif            
// 
InBlock.gif
            this.Dispose(); 
ExpandedSubBlockEnd.gif        }
 
InBlock.gif  
ExpandedBlockEnd.gif        
#endregion
  


总结

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

       UFTP调试成功,运行的结果还较理想。但它还有很多不足,它只实现了上传,没有下载;而且由于本人能力还有限,上传协议可能还不够完善,在此恳请大家提议。

转载于:https://www.cnblogs.com/thomas/archive/2005/01/30/99427.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值