可靠UDP传输的实现!

shenyi0106 2011-02-10 08:24:47
加精
一直纠结于UDP的可靠传输,在查看了UDT的相关介绍后,发现并不是我需要的,我需要的是一个可以进行多点传输的的可靠UDP。最终,还是自己慢慢把它完成了,虽然还不够好,不过总算出来个框架了,以后改就容易了 。
在算法上并没有什么特别的,就是不断的采用超时重发机制。在发送端,建立了一个庞大的发送缓冲区队列,每个发送过的发送单元都将自动被添加到这个发送缓冲区中,然后由维护线程来管理。在维护线程中,定时遍历所有的发送缓冲区,检查那些没有被确认且还没达到发送最大值限制的发送单元,然后将它们发送出去,以此类推,直到所有的发送单元都被确认或者都达到发送最大值限制。请看下面的发送单元结构:
     
//发送单元
typedef struct _UDT_SND_ITEM_
{
USHORT uBufLen; //chBuf的数据长度
USHORT uLimitCnt; //发送次数限制
SOCKET hSock; //UDP句柄
CHAR chBuf[DATA_BUFSIZE]; //要发送的数据,UDT头 + 数据
DWORD dwLastTime; //最后发送时间(如果为0xFFFFFFFF则表示已经确认)
SOCKADDR_IN To; //发送的目的地
}UDT_SND_ITEM;
在CUDTSend类中的变量 DWORD * m_pdwPos是用来维护发送单元的集合,当UDTSend函数将一个要发送的数据包拆分成独立的发送单元并发送时,都会依据这个发送单元的序号将该发送单元添加到m_pdwPos集合中,使该集合中的对应序号的地址就是这个发送单元。目前这个发送缓冲区的最大容量使65536,也就是最大可以存储65536个未确认的发送单元。
相比之下,接收类的设计就显的比较复杂,因为接收类要考虑来自不同主机所发送过来的数据,还要考虑每个主机发送的不同数据包,并且就算是同一个数据包,也还要按顺序接收每个单元数据,在组合这些单元数据为一个整数据包,针对以上问题,我通过定义以下的数据结构来完成功能:
//接收包单元
typedef struct _UDT_RECV_ITEM_
{
DWORD dwSeq; //序号
DWORD uRecvLen; //数据长度
CHAR chBuf[DATA_SNDSIZE]; //数据部分
}UDT_RECV_ITEM;




//数据包(接收单元的组合)
typedef struct _UDT_RECV_ITEMS_
{
DWORD dwSeqSpan; //包序号区间
USHORT uPacketCount; //包数量来自于包区间序号相减
USHORT uRecvCount; //已经接收的包数量
DWORD dwLastTime; //最后接收到包的时间
CCriticalSection cs_item; //接收单元同步对象
DWORD dwItemPos[1024]; //所有接收包单元集合
_UDT_RECV_ITEMS_ * ItemsNext; //指向下一个ITEMS结构
}UDT_RECV_ITEMS;


//主机结点(每个接收的主机信息)
typedef struct _UDT_RECV_PEER_
{
SOCKADDR_IN Peer; //发送端
DWORD dwLastTime; //最后更新时间
CCriticalSection cs_items; //包表示同步对象
_UDT_RECV_ITEMS_ * ItemsNext; //指向下一个ITEMS结构
_UDT_RECV_PEER_ * PeerNext; //指向下一个节点
}UDT_RECV_PEER;

以上三个结构通过以下示意图的方式连接起来,实现收包的功能
UDT_RECV_PEER ——> UDT_RECV_PEER ——> UDT_RECV_PEER ——>.......
|
|
V
UDT_RECV_ITEMS——>UDT_RECV_ITEM——>UDT_RECV_ITEM——>......
|
|
V
UDT_RECV_ITEMS
|
|
V
UDT_RECV_ITEMS
|
|
V
......

以上示意图的意思是说,如果收到的数据包来自不同的主机节点都会添加一个UDT_RECV_PEER节点形成一个主机节点链表,针对与每个主机可能会收到不同的数据包,采用在主机节点下串联UDT_RECV_ITEMS结构的方法存放数据包,针对每个接收包单元会存放在UDT_RECV_ITEMS结构下的dwItemPos[1024]成员中,该成员的每个元素都可以用来存放UDT_RECV_ITEM接收单元。以这样的结构来完成数据包的可靠接收,并完成从单一的接收单元组合成完整的数据包的过程,这整个过程都通过调用CUDTRecv类的UDTRecv函数来完成,该函数完成了从接收数据,到发送确认,再到存储接收单元,最后实现组包这一系列过程,并通过输出参数将接收到的数据包返回给调用者。

综合以上的说明,不难看出,虽然实现了可靠传输,但是并没有实现完全的可靠传输,因为受到发送缓冲的序号限制,最大只能同时存在65536个发送包,也就是说如果在整个发送过程中同时存在的未确认包超过这个限制,就会使发送包出现错误,并导致数据无法可靠传输;而且由于是尽可能的可到传输(限次发送),所以如果遇到网络情况恶劣的情况下,可能会导致部分发送数据超过发送最大值限制而被清除;因此这里介绍的可到传输以及相关代码只是实现了一个框架,并可以满足大部分情况,如果要满足所有情况,则需要不断的修改完善。

相关代码:点击下载
...全文
20432 241 打赏 收藏 转发到动态 举报
写回复
用AI写文章
241 条回复
切换为时间正序
请发表友善的回复…
发表回复
haopairs 2013-09-24
  • 打赏
  • 举报
回复
好东西
libingbing5210 2013-05-15
  • 打赏
  • 举报
回复
这个类 不知道怎么去调用啊!!网络编程新手,求了解的兄弟帮忙解释下,最好有个简单的实例,这样理解起来 完全OK了。
herenke123 2012-11-12
  • 打赏
  • 举报
回复
MARK ...刚学...支持楼主
xiaolomg 2012-10-07
  • 打赏
  • 举报
回复
把回帖帖子都看了,除了个别无良广告贴,很多精品啊!
lkwanguestc 2012-07-16
  • 打赏
  • 举报
回复
很好 很强大
MosWinter 2012-05-18
  • 打赏
  • 举报
回复
借鉴一下~~
无花果 2012-02-13
  • 打赏
  • 举报
回复
要做UDP可靠传输,特别是 共享端口,VTCP是个不错的解决方案。
http://www.cnasm.com/vtcpsdk

最专业的系统 805122102 (805122102)
2012-02-13 12:36:48
[删除该条消息]

我是想用udp打洞,这vtcp稳定传输
whg:无花果 (312016)
2012-02-13 12:37:39
[删除该条消息]

为了 提高打洞效率,应该复用端口,就是采用一个真实的UDP SOCKET句柄,来收发数据包。
whg:无花果 (312016)
2012-02-13 12:37:59
[删除该条消息]

实现步骤如下:
最专业的系统 805122102 (805122102)
2012-02-13 12:38:00
[删除该条消息]

哪个函数
whg:无花果 (312016)
2012-02-13 12:38:27
[删除该条消息]

1.vtcp_socket(...)创建一个VTCP句柄
whg:无花果 (312016)
2012-02-13 12:38:44
[删除该条消息]

2.vtcp_bind(...)绑定一个端口。
whg:无花果 (312016)
2012-02-13 12:39:01
[删除该条消息]

3.vtcp_listen(...)开启服务监听端口。
whg:无花果 (312016)
2012-02-13 12:39:36
[删除该条消息]

第3步是允许其他p2p点连接自己。
最专业的系统 805122102 (805122102)
2012-02-13 12:39:44
[删除该条消息]

噢,
whg:无花果 (312016)
2012-02-13 12:40:05
[删除该条消息]

但是现在 没有打洞,其他p2p无法知道你的出口地址。
可是我怎么去连接人家呢
whg:无花果 (312016)
2012-02-13 12:40:29
[删除该条消息]

4.用vtcp_io_xxx函数登录你自己的p2p服务器。
最专业的系统 805122102 (805122102)
2012-02-13 12:41:04
[删除该条消息]

这样啊,
whg:无花果 (312016)
2012-02-13 12:41:05
[删除该条消息]

p2p服务器,有源代码,p2p协议自己设计。
whg:无花果 (312016)
2012-02-13 12:41:21
[删除该条消息]

不必要照抄VTCP的p2p源代码。
最专业的系统 805122102 (805122102)
2012-02-13 12:42:17
[删除该条消息]

1.0的源代码跟11的原理是不是一样的
whg:无花果 (312016)
2012-02-13 12:42:53
[删除该条消息]

5.vtcp_socket_share(...)创建一个 共享vtcp句柄。
最专业的系统 805122102 (805122102)
2012-02-13 12:43:56
[删除该条消息]

明白了
最专业的系统 805122102 (805122102)
2012-02-13 12:44:26
[删除该条消息]

你的意思就是说,先要创建一个 服务端,然后share一个客户端去连接
whg:无花果 (312016)
2012-02-13 12:44:36
[删除该条消息]

恩。
6.直接用share句柄去vtcp_connect(。。。)其他点。
最专业的系统 805122102 (805122102)
2012-02-13 12:45:30
[删除该条消息]

如果这样share出来的客户端,如果有消息过来的话,是客户端收到消息呢,还是服务端收到消息
whg:无花果 (312016)
2012-02-13 12:45:47
[删除该条消息]

7.在连接其他点时,应该用vtcp_io_xxx与p2p服务器联系,要求服务器帮忙打洞。
aimmaker 2011-10-25
  • 打赏
  • 举报
回复
[Quote=引用 220 楼 nobugtodebug 的回复:]

楼主,握个手先。
我这段时间也正在研究这个。需求和你的一样。
不知道楼主有没有研究过libjingle的pseudotcp.我们的项目用的是这个。从功能上来讲,完全满足,但就是传输速度上比TCP慢很多。这段时间测试下来,在10M的以太网中,pseudotcp的速度只有TCP的30%左右。
公网环境下还没有测试数据。
由于速度的原因,我在考虑寻找其他的方案。自己实现一个的想法放在最后,个人……
[/Quote]

220楼用的可是 tunnel session? 我最近在做一个libjingle的Java客户端 用来传输数据
fdsook 2011-10-23
  • 打赏
  • 举报
回复
这个怎么使用的呀。楼主可以发个例子不?
yzb__2011 2011-05-13
  • 打赏
  • 举报
回复
感谢大神带领
Leon4NZ 2011-05-06
  • 打赏
  • 举报
回复
源码积分不够,下不了,怨念啊
cinqonlines 2011-04-07
  • 打赏
  • 举报
回复
还是用TCP。
juckxu 2011-03-03
  • 打赏
  • 举报
回复
3Q!学习了.
yuanshangda 2011-02-28
  • 打赏
  • 举报
回复
UDP与TCP。
lenovo1792 2011-02-21
  • 打赏
  • 举报
回复
虽然看不懂,但是我还顶
nobugtodebug 2011-02-21
  • 打赏
  • 举报
回复
楼主,握个手先。
我这段时间也正在研究这个。需求和你的一样。
不知道楼主有没有研究过libjingle的pseudotcp.我们的项目用的是这个。从功能上来讲,完全满足,但就是传输速度上比TCP慢很多。这段时间测试下来,在10M的以太网中,pseudotcp的速度只有TCP的30%左右。
公网环境下还没有测试数据。
由于速度的原因,我在考虑寻找其他的方案。自己实现一个的想法放在最后,个人感觉这条路很不靠谱。因为我们没有太多时间在各种网络条件下去测试从而让这块代码达到相当的稳定可靠。
xiaogang19880817 2011-02-20
  • 打赏
  • 举报
回复
非常感谢,正在查这方面的资料
tj_swjtu 2011-02-18
  • 打赏
  • 举报
回复
楼主强大,但为啥不用ACE呢?
mwangyuqian 2011-02-18
  • 打赏
  • 举报
回复
伪TCP
鉴定完毕
xlg3030 2011-02-18
  • 打赏
  • 举报
回复
支持原创!
加载更多回复(90)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧