ImageVerifierCode 换一换
格式:DOCX , 页数:12 ,大小:18.32KB ,
资源ID:24212526      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/24212526.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(转 UDP模拟TCP滑动窗口实现数据安全可靠传输.docx)为本站会员(b****2)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

转 UDP模拟TCP滑动窗口实现数据安全可靠传输.docx

1、转 UDP模拟TCP滑动窗口实现数据安全可靠传输转 UDP模拟TCP滑动窗口实现数据安全可靠传输(转)UDP模拟TCP滑动窗口实现数据安全可靠传输(C#)日期:2010-05-26|最近需要实现P2P也就是需要做NAT穿透,原来写的TCP传输就出现问题了,因为TCP不能很好的实现内网的穿透,因此最好用UDP来实现传输。可是UDP存在一些可靠性上的问题,主要是UDP是面向无连接的协议,传输中数据包丢失时没有重传,而且由于网络环境因素可能会出现数据包的乱序的情况。UDP的特点导致其不能方便的应用于需要保证数据可靠性的场合,比如文件传输等。现在一般P2P软件的做法应该是在应用层包装一下UDP协议,实

2、现UDP的可靠传输。在网上搜了下,本以为应该很多有现成的东西的,结果发现太少了。先搜到了一份Delphi版的,网址,可惜我基本不懂Delphi;然后还在sourceforge上发现一个叫UDT的开源项目,官方的网址是,这个用C+写的,封装成了DLL,但研究了下觉得我用C#还是很难调用。最后决定自己动手写一个了,无非是模拟一下TCP嘛此次实现采用了TCP的滑动窗口原理。在解释滑动窗口前先看看ACK的应答策略,一般来说,发送端发送一个TCP数据报,那么接收端就应该发送一个ACK数据报。但是事实上却不是这样,发送端将会连续发送数据尽量填满接受方的缓冲区,而接受方对这些数据只要发送一个ACK报文来回应

3、就可以了,这就是ACK的累积特性,这个特性大大减少了发送端和接收端的负担。滑动窗口本质上是描述接受方的TCP数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据。如果发送方收到接受方的窗口大小为0的TCP数据报,那么发送方将停止发送数据,等到接受方发送窗口大小不为0的数据报的到来。原理基本上就是这样,在本程序里,接收放和发送方要事先约定好传输的每个包的数据大小及传输一组包的包数,也就是窗口大小。发送方发送一组数据后等待接收方的ACK确认,确认超时后重发,重发次数超过额定次数后视为连接中断。另外需要对每个数据包加了一个包的标识字节,我把这个字节放到了每个包的最后面,因此发送方

4、发送给接收方的每个包含传输数据的包内容长度肯定大于等于2字节,接收方收到1个字节的包会丢弃,这样设计正好可以利用发送一个字节的包来保持连接不中断,可以应用在某些暂时不需要数据传输但需要保持此次连接以便随时可以继续传输的情况(比如我的程序里)。然后说一个我的数据包标识字节的设计吧,一个byte共8bit,前四位(0-15)来表示组序号,中间三位表示组内包序号(0-9),最后一位是发送完毕标记1234 567 8|组序号组内包序号发送完毕标记接收端收到一个包后提取标识字节,如果组序号不是当前组序号则丢弃,否则根据组内包号记录该包,然后检查该组是否已经发送完毕,即窗口是否塞满,是的话发送ACK确认包

5、(确认包内容为当前组序号),然后当前组序号=(当前组序号+1)%16。基本就是这样了,测试了一下,本地传输的速度还行,传了个200M+的文件用了6.3秒。然后就是代码了,我把这个类封装成DLL来调用了。using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Net;using System.Net.Sockets;using System.IO;namespace Transfer/*Secured UDP Tran

6、sfer Class-UDP安全传输类采用TCP滑动窗口原理在应用层解决UDP协议传输的丢包,乱序等问题,实现UDP可靠传输;要求传入的UdpClient实例为已连接的实例,即调用此类的方法前请先执行初始化实例并连接;发送接收的数据类采用Stream,可应用到其子类FileStream,MemoryStream等*/public class SUdpTransferprivate const int defaultPacketSize=513,defaultGroupSize=7;/默认UDP包数据内容大小、组(窗口)大小private const int confirmTimeOut=100

7、0;/确认超时时间private const int maxResendCount=4;/最大重发次数(超出则认为连接断开)private const int receiveTimeOut=4000;/接收超时时间private UdpClient client;/已连接的UdpClient实例private AutoResetEvent confirmEvent=new AutoResetEventfalse;/等待确认回复用的事件private int groupSeq;/当前传送的组序号private Thread thListen;/发送端确认包接收线程private bool err

8、or;/出错标志public SUdpTransferUdpClient clientthis.client=client;/数据发送函数,返回值0:发送成功,-1:发送失败public int SendStream streamreturn Sendstream,defaultPacketSize,defaultGroupSize;public int SendStream stream,int packetSize,int groupSizeerror=false;int dataSize=packetSize-1;int i,read,readSum;byte flag=0;/UDP包中

9、的标志字节,包含组序号,包序号(即组内序号),发送结束标志int resendCount=0;/重发次数标记try/启动确认包接收线程thListen=new Threadnew ThreadStartListen;thListen.IsBackground=true;thListen.Start;groupSeq=0;stream.Seek0,SeekOrigin.Begin;confirmEvent.Reset;while trueif error return-1;readSum=0;/记录读取字节数以便重发时Stream的回退for i=0;i groupSize;i+flag=byt

10、ebytegroupSeq 4bytei 1;byte buffer=new bytepacketSize;read=stream.Readbuffer,0,dataSize;readSum+=read;if read=dataSizeif stream.Position=stream.Length/已经读完flag|=0x01;/结束标记位置1 bufferread=flag;/数据包标志字节放于每个包的最后client.Sendbuffer,read+1;break;bufferread=flag;client.Sendbuffer,read+1;else if read 0/已经读完fl

11、ag|=0x01;/结束标记位置1 bufferread=flag;/数据包标志字节放于每个包的最后client.Sendbuffer,read+1;break;elsebreak;if error return-1;if confirmEvent.WaitOneconfirmTimeOut/收到确认if intflag 0x01=1/发送完毕break;groupSeq=groupSeq+1%16;resendCount=0;else/未收到确认if resendCount=maxResendCount/超出最大重发次数thListen.Abort;return-1;/重发stream.Se

12、ek-1*readSum,SeekOrigin.Current;resendCount+;/发送完毕,关闭确认包接收线程thListen.Abort;catch/异常thListen.Abort;return-1;return 0;/确认包接收线程函数private void ListenIPEndPoint ipep=new IPEndPointIPAddress.Any,0;trywhile truebyte confirm=client.Receiveref ipep;if intconfirm0=groupSeq/收到确认confirmEvent.Set;/激活接收确认事件else i

13、f confirm0=0xFF/传输中断命令error=true;break;catch/异常error=true;/数据接收函数,返回值0:接收成功,-1:接收失败public int Receiveref Stream streamreturn Receiveref stream,defaultPacketSize,defaultGroupSize;public int Receiveref Stream stream,int packetSize,int groupSizeIPEndPoint ipep=new IPEndPointIPAddress.Any,0;int groupFla

14、g=new intgroupSize;byte groupData=new bytegroupSize;byte flag;/UDP包中的标志字节,包含组序号,包序号(即组内序号),发送结束标志int groupSeq,packetSeq,myGroupSeq;int dataSize=packetSize-1;int i,endFlag,currentGroupSize;int socketRecieveTimeOut=client.Client.ReceiveTimeout;/保存原来的接收超时时间tryclient.Client.ReceiveTimeout=receiveTimeOut

15、;/设置接收超时时间currentGroupSize=groupSize;myGroupSeq=0;while truebyte data=client.Receiveref ipep;if data.Length 2/最小数据长度为2字节if data.Length=1 data0=0xFF/传输中断命令client.Client.ReceiveTimeout=socketRecieveTimeOut;/恢复原来的接收超时时间return-1;continue;flag=datadata.Length-1;/数据包标志字节在每个数据包的最后groupSeq=flag 4;/前四位:组序号pa

16、cketSeq=flag 0x0F 1;/中间三位:包序号endFlag=flag 0x01;/最后一位:发送结束标记if groupSeq!=myGroupSeq/不属于希望接受的数据包组if groupSeq+1%16=myGroupSeq/上一组回复的确认未收到byte confirmData=new bytebytegroupSeq;client.SendconfirmData,confirmData.Length;/回复确认continue;if groupFlagpacketSeq=1/已接收该包则丢弃continue;groupFlagpacketSeq=1;/记录groupDa

17、tapacketSeq=data;/暂存数据if endFlag=1/收到含结束标记的包currentGroupSize=packetSeq+1;/改变当前组的窗口大小/检测是否该组包已全部接收for i=0;i currentGroupSize;i+if groupFlagi=0 break;if i=currentGroupSize/已全部接收/写入数据for i=0;i currentGroupSize;i+stream.WritegroupDatai,0,groupDatai.Length-1;byte confirmData=new bytebytegroupSeq;client.S

18、endconfirmData,confirmData.Length;/回复确认client.SendconfirmData,confirmData.Length;/回复两次,确保收到if endFlag=1/已收到结束包则退出break;myGroupSeq=myGroupSeq+1%16;currentGroupSize=groupSize;Array.CleargroupFlag,0,groupData.Length;catch/异常client.Client.ReceiveTimeout=socketRecieveTimeOut;/恢复原来的接收超时时间return-1;client.C

19、lient.ReceiveTimeout=socketRecieveTimeOut;return 0;PS:其实真想给这个类起名为RUDPTransfer的,可是有RUDP协议,是传输层的,wikipedia这么说:RUDP is not currently aformal standard,however it was described in an IETF internet-draft in 1999历史上的今天:C/C+中对文件的读写操作2010-05-26随机文章:C/C+中对文件的读写操作2010-05-26(转)long long类型的网络字节转换2010-05-24 2010-05-24

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1