zoukankan      html  css  js  c++  java
  • 可靠的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();
    }

  • 相关阅读:
    前端PHP入门-030-文件函数API
    前端PHP入门-029-文件操作-掌握级别
    前端PHP入门-028-文件操作-掌握级别
    前端PHP入门-027-数组常用函数-掌握级别
    SVM 支持向量机
    java 设计模式
    Linear Regreesion
    java 小结1(static ,final,泛型)
    概念介绍(机器学习)
    集成学习 概念介绍
  • 原文地址:https://www.cnblogs.com/toosuo/p/2286232.html
Copyright © 2011-2022 走看看