可靠的UDP編程

    大家都知道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();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章