可靠的UDP编程(ENET库)

大家都知道UDP这个东西太不可靠了,存在着乱序,丢包,包重复等缺点,但它的速度快,包有界等优点,但在实际编程中要自己处理乱序啊之类的问题会发疯的。也许大家说用TCP就得了,第一点TCP的速度比较慢,第二个TCP是一个数据流一样的东西,我们要传数据的话还得处理数据的分界问题,也挺麻烦的。

    针对这个问题,ENET这个库实现了一个性能介于TCP与UDP之间,完成可靠(不丢包,按序),保持数据的分界的优点。编程起来也挺方便的。下载到http://enet.bespin.org/SourceDistro.html,目前最新版本是1.2,然后按照说明编译出库出来。

    使用ENET库就可以实际可靠的UDP编程,一个简单的例子如下:

///////服务器

#include <iostream>
#include <enet/enet.h>
using namespace std;

void main()
{
//初始化enet库
if(enet_initialize())
{
     cout <<"初始化失败" <<endl;
     return;
}

//下面创建服务器
ENetAddress address;
address.host=ENET_HOST_ANY;
address.port=1234;

ENetHost *server;
server=enet_host_create(&address, //主机地址
                                           64,        //允许的连接数
                                            0,
                                           0);        //自动管理带宽
if(server==NULL)
{
     cout <<"创建主机对象失败" <<endl;
     enet_deinitialize();
    return;
}


//下面开始收数据等
ENetEvent event;
while(enet_host_service(server,&event,5000)>=0)
{
    if(event.type==ENET_EVENT_TYPE_CONNECT) //有客户机连接成功
     {
      static unsigned int num=0;
      ENetAddress remote=event.peer->address; //远程地址
      char ip[256];
      enet_address_get_host_ip(&remote,ip,256);
      cout <<"ip:" <<ip <<" 已经连接,序号:" <<num <<endl;
      event.peer->data=(void*)num++;
    }
     else if(event.type==ENET_EVENT_TYPE_RECEIVE) //收到数据
     {
      cout <<"收到序号" <<event.peer->data <<"的数据,从" <<event.channelID <<"通道发送" <<endl;
      cout <<"数据大小:" <<event.packet->dataLength <<endl;
      cout <<"数据:" <<(char*)event.packet->data <<endl;
      enet_packet_destroy(event.packet);    //注意释放空间
      cout <<endl;
     }
     else if(event.type==ENET_EVENT_TYPE_DISCONNECT) //失去连接
     {
      cout <<"序号" <<event.peer->data <<"远程已经关闭连接" <<endl;
    }
}

enet_deinitialize();
}

///////客户端

#include <iostream>
#include <enet/enet.h>
using namespace std;

void main()
{
//初始化enet库
if(enet_initialize())
{
   cout <<"初始化失败" <<endl;
   return;
}

//创建本地HOST对象
ENetHost *client=enet_host_create(NULL,
           1,   //只允许连接一个服务器
           0,
           0);
if(client==NULL)
{
   cout <<"创建客户端失败" <<endl;
   return;
}


//连接到服务器
ENetAddress svraddr;
enet_address_set_host(&svraddr,"127.0.0.1");
svraddr.port=1234;

ENetPeer *server=enet_host_connect(client,&svraddr,3); //client连接到svraddr对象,共分配三个通道
if(server==NULL)
{
   cout <<"连接服务器失败" <<endl;
   return;
}

ENetEvent event;
//连接成功后必须调用enet_host_service来最终确认
if (enet_host_service (client, &event5000) > 0 &&
        event.type == ENET_EVENT_TYPE_CONNECT)
    {
        cout <<"连接服务器成功" <<endl;
    }
    else
    {
        enet_peer_reset (server);
        cout <<"连接服务器失败" <<endl;
   return;
    }
   

//下面开始发数据
ENetPacket *packet=enet_packet_create(NULL,78,ENET_PACKET_FLAG_RELIABLE); //创建包
strcpy((char*)packet->data,"hi,哈哈");
enet_peer_send(server,1,packet);

ENetPacket *packet1=enet_packet_create(NULL,86,ENET_PACKET_FLAG_RELIABLE); //创建包
strcpy((char*)packet1->data,"你好啊,呵呵");
enet_peer_send(server,2,packet1);

enet_host_flush (client); //必须使用这个函数或是enet_host_service来使数据发出去


//关闭连接
enet_peer_disconnect (server,0);
//等待关闭成功
while (enet_host_service (client, &event5000)>0)
    {
        switch (event.type)
        {
   case ENET_EVENT_TYPE_RECEIVE:
            enet_packet_destroy (event.packet);
            break;

        case ENET_EVENT_TYPE_DISCONNECT:
            cout <<"已经成功断开连接" <<endl;
    enet_deinitialize();
            return;
        }
    }

//这里就是关闭失败,强制重置
enet_peer_reset(server);
cout <<"强制重置" <<endl;

enet_deinitialize();
}

原文地址:https://www.cnblogs.com/toosuo/p/2286232.html