开源可靠UDP协议汇总分析

项目需求:使用UDP协议,将视频数据(约30MBytes/Sec) ,尽可能正确的传递给与设备直连的PC.错误的数据直接丢弃.
老大给出的信息:UDP不会乱序,因为没有人会特意打乱数据,既然给网卡送数据是顺序送的,当然应该是顺序的.
实测的结果 :UDP的数据包一定是乱的.
因为这就是UDP的特征之一. 哲学一点说,就是如果不维护某一个特征,则必然不会出现.
按照的解释, 对一个混乱的系统,不做规范和梳理,系统必然会朝着熵增加的趋势,也就是越来越混乱的方向发展的.

UDP另一个的让人崩溃的特点,除了乱序之外,是数据的不可到达性,即不保证所有的数据都会送达.
还有一个特点就是 : UDP的分片, 一般都是限制在1400(最大1476,但是为了保险起见,1400是一个经验值).
所以,对所有的数据,都需要手动分片;在接收端,就要对应的组装起来.

这个时候,就有一个疑问了,既然使用UDP,又需要做分片,又需要确保正确性,那么为何不直接使用TCP呢?
这是个好问题.
答案就是,项目一定要求使用UDP.
一个好处是,服务器在不知道客户端存在或者是否已经启动的情况下,就可以向某个地址一直发送数据.这点TCP是无法做到的.
顺便提一下, UDP的理论速度略大于TCP,但是这点提升,对于复杂的实现逻辑来说,我宁愿不要…

在尝试自己造轮子,做了半个月的尝试,使用UDP协议做一个可靠的传输协议之后,现实毒打了我.
那么问题来了,为什么不使用已经存在的类似的库来做呢?
这是因为:我需要在嵌入式端和PC的VS studio端分别做Server和Client.一般的库,在Windows下的C++可能没问题, 但是没有对应的嵌入式代码,或者一些Windows特有的h文件,导致无法移植.而且有些库的体积巨大,学习成本高昂,而且更致命的是,也不确定花了时间之后,这个库就能够正常运作. 项目时间不允许这么做.

不过最终还是老老实实的分析了几个知名的库,将优缺点分析清楚. 最终采用的是ENet.
下面将研究的结果分享出来.

名称地址主要语言轻量?特点/优点
RakNethttps://github.com/facebookarchive/RakNetC C++ HTML较重
UDThttps://sourceforge.net/projects/udt/C++较轻
asio2https://github.com/zhllxt/asio2C++ C较轻只有h文件 方便移植
KCPhttps://github.com/skywind3000/kcpC C++很轻只有4个主要文件,主要用来改善TCP和UDP的延迟问题
ENET 可靠UDPhttp://enet.bespin.org/index.htmlC++较轻可靠和非可靠可选.都是peer的概念,没有明确的Server和Client

你也可以从这里下载源代码
https://github.com/lsalzman/enet

这是一个在油管上非常好的例子,你可以跟着他的前2章来实现一个简单的可通信的Server和Client
Basic ENet Tutorial Series - Server/Client Setup (1/5)
他们的官网给出了代码
https://usergames.net/tutorials/enet/part1
也就是这样,可以直接复制来参考.


/* ./server/main.c */

#include <stdio.h>
#include <enet/enet.h>

int main (int argc, char ** argv)
{
    if (enet_initialize () != 0)
    {
        fprintf (stderr, "An error occurred while initializing ENet.\n");
        return EXIT_FAILURE;
    }
    atexit (enet_deinitialize);

ENetEvent event;
ENetAddress address;
ENetHost* server;

/* Bind the server to the default localhost.     */
/* A specific host address can be specified by   */
/* enet_address_set_host (& address, "x.x.x.x"); */
address.host = ENET_HOST_ANY; // This allows
/* Bind the server to port 7777. */
address.port = 7777;



server = enet_host_create (&address	/* the address to bind the server host to */,
				32	/* allow up to 32 clients and/or outgoing connections */,
				1	/* allow up to 1 channel to be used, 0. */,
				0	/* assume any amount of incoming bandwidth */,
				0	/* assume any amount of outgoing bandwidth */);

if (server == NULL)
{
	printf("An error occurred while trying to create an ENet server host.");
	return 1;
}

// gameloop
while(true)
{
	ENetEvent event;
	/* Wait up to 1000 milliseconds for an event. */
	while (enet_host_service (server, & event, 1000) > 0)
	{
		switch (event.type)
		{
			case ENET_EVENT_TYPE_CONNECT:
				printf ("A new client connected from %x:%u.\n",
		  		event.peer -> address.host,
				event.peer -> address.port);
			break;

			case ENET_EVENT_TYPE_RECEIVE:
				printf ("A packet of length %u containing %s was received from %s on channel %u.\n",
					event.packet -> dataLength,
					event.packet -> data,
					event.peer -> data,
					event.channelID);
					/* Clean up the packet now that we're done using it. */
					enet_packet_destroy (event.packet);
			break;

			case ENET_EVENT_TYPE_DISCONNECT:
				printf ("%s disconnected.\n", event.peer -> data);
				/* Reset the peer's client information. */
				event.peer -> data = NULL;
		}
	}
}

enet_host_destroy(server);

return 0;
}

一些参考:

何老师给我的例子
https://blog.csdn.net/yuanchunsi/article/details/70244338

https://usergames.net/tutorials/enet/part1
API
http://enet.bespin.org/enet_8h.html
教程
http://enet.bespin.org/Tutorial.html
ENet教程翻译
https://www.cnblogs.com/allen8807/archive/2010/12/10/1900473.html

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔尊moon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值