Enet入门(译)

转自:

http://hi.baidu.com/ejoywx/item/903c2dc690c02bc1984aa0a3

[译者注]
enet作为一个基于UDP通信的网络通信开发包,提供近似TCP的可靠网络通信特性。
希望国内有人喜欢上enet。我才接触enet,刚刚用MinGW和VC9编译出了enet库,就动手翻译enet的入门文档。
ENet官方网站:http://enet.bespin.org/

1、初始化
你在使用ENet时应该包含头文件<enet/enet.h>。请不要不用目录前缀而直接包含<enet.h>,那样可能会导致文件名与其他系统相混淆。
在使用ENet库之前,你必须调用enet_initialize()来初始化这个库。当程序退出时,你应该调用enet_deinitialize() 使enet库可以清除任何使用的资源。
    #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);
        ...
        ...
        ...
    }

2、创建enet服务器
ENet中的服务器是用enet_host_create()构造的。 你必须指定一个地址给服务器,这个地址用于接收数据和新连接,以及连接的对等实体的最大允许值。 除了ENet的动态流量控制算法,你可以选择性的指定服务器的上行和下行带宽(单位是字节/秒)从而ENet可以尝试静态地管理和连接的对等实体间的带宽资源;将这个两个值指定为0,将导致ENet完全依赖它自身的动态流量控制算法来管理带宽。
当一个主机创建了一个enet服务器后,这个服务器可以用enet_host_destroy()来销毁。所有的连接到这台服务器的对等实体将被重设,这台服务器所使用的资源将会被释放。
    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;
    /* Bind the server to port 1234. */
    address.port = 1234;
    
    server = enet_host_create (& address /* the address to bind the server host to */, 
                                 32      /* allow up to 32 clients and/or outgoing connections */,
                                  2      /* allow up to 2 channels to be used, 0 and 1 */,
                                  0      /* assume any amount of incoming bandwidth */,
                                  0      /* assume any amount of outgoing bandwidth */);
    if (server == NULL)
    {
        fprintf (stderr,"An error occurred while trying to create an ENet server host.\n");
        exit (EXIT_FAILURE);
    }
    ...
    ...
    ...
    enet_host_destroy(server);

3、创建enet客户端
客户端同样是enet_host_create创建的,只是没有指定绑定主机的地址。如下面的例子,带宽可以指定给客户端主机。对等实体计算控制连接到其他服务器主机可以同时打开的的最大连接数。
    ENetHost * client;
    client = enet_host_create (NULL /* create a client host */,
                1 /* only allow 1 outgoing connection */,
                2 /* allow up 2 channels to be used, 0 and 1 */,
                57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */,
                14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */);
    if (client == NULL)
    {
        fprintf (stderr,"An error occurred while trying to create an ENet client host.\n");
        exit (EXIT_FAILURE);
    }
    ...
    ...
    ...
    enet_host_destroy(client);

4、管理enet主机    ENet使用轮询事件模型来通知程序重要事件。ENet主机用enet_host_service()轮训事件,该函数中有一个可选的超时值(单位是毫秒)可以用来指定ENet将要轮轮询多久; 如果超时值设为0,若没有事件调度则enet_host_service()将立即返回. 若在指定的超时时间内有事件被调度则enet_host_service()返回1.
当前ENet仅仅支持四种类型的重要事件:
在指定超时时间内没有事件发生,ENET_EVENT_TYPE_NONE 事件类型会被返回。enet_host_service()将会随着这个事件返回0。
当一个新的客户端主机已连接到服务器主机或者成功地与远程主机建立了连接时,ENET_EVENT_TYPE_CONNECT事件类型会被返回。事件结构的“peer”域仅仅对于本事件有效并包含了最新的连接的对等实体。
当来自连接的对等实体的数据包接收时,ENET_EVENT_TYPE_RECEIVE事件类型会被返回. “peer”域包含了发送数据包的对等实体,“channelID”域指示数据包被发送的信道,“packet”域指示被发送的数据包。当你存取了在“packet”域包含的packet的内容后,必须用enet_packet_destroy()销毁掉它。
当连接的对等实体显式打开连接或者超时,ENET_EVENT_TYPE_DISCONNECT 事件类型会被返回. 事件结构的“peer”域 仅仅对于本事件有效并包含了断开的对等实体。一个断开连接事件上的peer的“data”域依然有效,并且必须被显式重设。
    ENetEvent event;
    
    /* Wait up to 1000 milliseconds for an event. */
    while (enet_host_service (client, & 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);

            /* Store any relevant client information here. */
            event.peer -> data = "Client information";

            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&apos;re done using it. */
            enet_packet_destroy (event.packet);
            
            break;
           
        case ENET_EVENT_TYPE_DISCONNECT:
            printf ("%s disconected.\n", event.peer -> data);

            /* Reset the peer&apos;s client information. */

            event.peer -> data = NULL;
        }
    }
    ...
    ...
    ...

5、发送数据包给enet对等实体(peer)
ENet中数据包是用 enet_packet_create()创建的,该函数指定了数据包的大小。可选择地,可以指定初始数据复制到数据包中。
某些标志也应该提供给enet_packet_create()以控制各种包的特征。、
ENET_PACKET_FLAG_RELIABLE规定数据包必须被可靠地投递。一个可靠的数据包必须保证被交付,大量的重试尝试将会被做的直到接收到数据送往的远程主机的确认。如果一定数量的尝试尝试被做后依旧没有收到确认,ENet将会认为对等实体已经断开了连接并强行重设连接。如果标志没有被指定,数据包将会被设定成不可靠的数据包,将不会有重试重试被做也不会有确认生成。
通过enet_packet_resize()可以改变数据包的大小(延长或者缩短).
调用enet_peer_send()将一个数据包被发送到远程主机. enet_peer_send()接受一个信到值并在该信道上将数据包发送给一个给定的对等实体。一旦通过enet_peer_send()数据包提交给ENet处理,ENet将负责它的释放从而不需要对该数据包调用enet_packet_destroy()。
在一个给定的主机上,通过一个这个指定的信到编号,也可以使用enet_host_broadcast()来发送数据包给所有连接的对等实体,如同使用enet_peer_send().
当enet_host_service()被调用,排队中的数据包才会被发送。另外,enet_host_flush() 将会把队列中的所有数据包全部发送出去而不会触发任何事件。
    /* Create a reliable packet of size 7 containing "packet\0" */
    ENetPacket * packet = enet_packet_create ("packet", 
                                              strlen ("packet") + 1, 
                                              ENET_PACKET_FLAG_RELIABLE);

    /* Extend the packet so and append the string "foo", so it now */
    /* contains "packetfoo\0"                                      */
    enet_packet_resize (packet, strlen ("packetfoo") + 1);
    strcpy (& packet -> data [strlen ("packet")], "foo");
    
    /* Send the packet to the peer over channel id 0. */
    /* One could also broadcast the packet by         */
    /* enet_host_broadcast (host, 0, packet);         */
    enet_peer_send (peer, 0, packet);
    ...
    ...
    ...
    /* One could just use enet_host_service() instead. */
    enet_host_flush (host);

6、断开enet对等实体的连接
enet_peer_disconnect()可以使等端断开连接。 一个断开链接请求将会发送给远程主机,且在最终断开链接前ENet将会等待一个来自远程主机的确认。当断开操作成功完成,事件ENET_EVENT_TYPE_DISCONNECT 将会被产生。
通常超时也被应用于断开连接的确认,并且如果超时时间到还没有确认被接收到,对等实体将会被强制断开连接。
enet_peer_reset()将会强制断开对等实体的连接。远程主机将不会得到任何连接断开的通知,远程主机将会发生超时. 没有事件被触发。
 ENetEvent event;
    
    enet_peer_disconnect (peer, 0);

    /* Allow up to 3 seconds for the disconnect to succeed
 and drop any packets received packets.
     */
    while (enet_host_service (client, & event, 3000) > 0)
    {
        switch (event.type)
        {
        case ENET_EVENT_TYPE_RECEIVE:
            enet_packet_destroy (event.packet);
            break;

        case ENET_EVENT_TYPE_DISCONNECT:
            puts ("Disconnection succeeded.");
            return;
        ...
        ...
        ...
        }
    }
    
    /* We&apos;ve arrived here, so the disconnect attempt didn&apos;t */
    /* succeed yet.  Force the connection down.             */
    enet_peer_reset (peer);
    ...
    ...
    ...

7、连接到enet主机
对远程主机的连接是用enet_host_connect()来初始化的。它接受的参数为将要连接的远程主机的地址,分配给通信用的信道编号。如果N条信道被分配使用,则信道的编号将是从0到N-1。 表示连接尝试的对等实体被返回,或者若没有可用的用来初始化连接的对等实体则返回NULL。当连接尝试成功完成,事件ENET_EVENT_TYPE_CONNECT将会被触发。如果连接尝试超时或者失败,事件ENET_EVENT_TYPE_DISCONNECT将会被触发。

    ENetAddress address;
    ENetEvent event;
    ENetPeer *peer;

    /* Connect to some.server.net:1234. */
    enet_address_set_host (& address, "some.server.net");
    address.port = 1234;

    /* Initiate the connection, allocating the two channels 0 and 1. */
    peer = enet_host_connect (client, & address, 2, 0);    
    
    if (peer == NULL)
    {
       fprintf (stderr, 
                "No available peers for initiating an ENet connection.\n");
       exit (EXIT_FAILURE);
    }
    
    /* Wait up to 5 seconds for the connection attempt to succeed. */
    if (enet_host_service (client, & event, 5000) > 0 &&
        event.type == ENET_EVENT_TYPE_CONNECT)
    {
        puts ("Connection to some.server.net:1234 succeeded.");
        ...
        ...
        ...
    }
    else
    {
        /* Either the 5 seconds are up or a disconnect event was */
        /* received. Reset the peer in the event the 5 seconds   */
        /* had run out without any significant event.            */
        enet_peer_reset (peer);

        puts ("Connection to some.server.net:1234 failed.");
    }
    ...
    ...
    ...

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值