天天看点

Enet学习(三)--enet_host_service

enet_host_service函数的功能是等待event事件的状态,并且在host和peer端来回移动,timeout是超时判断。因此服务端和对端都应该调用该函数。

返回大于0是在limit时间内收到有事件;等于0是没有事件,小于0是失败。

int
enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout)
{
    enet_uint32 waitCondition;
 
    if (event != NULL)
    {
        event -> type = ENET_EVENT_TYPE_NONE;
        event -> peer = NULL;
        event -> packet = NULL;
 
        switch (enet_protocol_dispatch_incoming_commands (host, event))
        {
        case 1:
            return 1;
 
        case -1:
#ifdef ENET_DEBUG
            perror ("Error dispatching incoming packets");
#endif
            return -1;
 
        default:
            break;
        }
    }
   host -> serviceTime = enet_time_get ();
    
    timeout += host -> serviceTime;
 
    do
    {
       if (ENET_TIME_DIFFERENCE (host -> serviceTime, host -> bandwidthThrottleEpoch) >= ENET_HOST_B»
         enet_host_bandwidth_throttle (host);
 
     //发送数据包函数
       switch (enet_protocol_send_outgoing_commands(host, event, 1))  
       {
       case 1:
          return 1;
 
       case -1:
#ifdef ENET_DEBUG
          perror (“Error sending outgoing packets"”);
#endif
          return -1;
       default:
          break;
       }
 
//接收数据函数
       switch (enet_protocol_receive_incoming_commands(host, event))
       {
       case 1:
          return 1;
 
       case -1:
#ifdef ENET_DEBUG
          perror (“Error receiving incoming packets”);                                               
#endif
         return -1;
 
       default:
          break;
       }
 //发送
       switch (enet_protocol_send_outgoing_commands (host, event, 1))
       {
       case 1:
          return 1;
 
       case -1:
#ifdef ENET_DEBUG
          perror (“Error sending outgoing packets"”);
#endif
 
          return -1;
 
       default:
          break;
       }
 
       if (event != NULL)
       {
          switch (enet_protocol_dispatch_incoming_commands (host, event))
          {
          case 1:
             return 1;
 
          case -1:
#ifdef ENET_DEBUG
             perror ("Error dispatching incoming packets");
#endif
                                                                                                     
             return -1;
         default:
             break;
          }
       }
 
       if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout))
         return 0;
 
       do
       {
          host -> serviceTime = enet_time_get ();
 
          if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout))
            return 0;
 
          waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT;
 
          if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host»
            return -1;
       }
       while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT);
 
       host -> serviceTime = enet_time_get ();
    } while (waitCondition & ENET_SOCKET_WAIT_RECEIVE);
 
    return 0; 
}
           

可以看到,函数中是通过调用enet_protocol_send_outgoing_commands函数来发送数据,outgoing即为将要发出的。

具体的service和client如何交互通信,目前还没仔细调试,暂且画上本人的初期理解:

Enet学习(三)--enet_host_service

该函数有点长,但是不用担心,结构很简单清晰。while和for为主要的循环。

根据这个函数可以知道,ENET的可靠传输是通过重传机制来保证可靠的,但是一旦有包传输停止或者网络不好无法传输某个包,传输会一直循环发送这个包,直到连接终止。因此函数中计算的丢包率是从某个包开始一直到最后的包个数占总包数的比例。

static int                                       
enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts)
{                                                                                            
    enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)];
    ENetProtocolHeader * header = (ENetProtocolHeader *) headerData;
    ENetPeer * currentPeer;     //要传输给对端的包,保存在host的peer里              
    int sentLength;                              
    size_t shouldCompress = 0;                   
                                                 
    host -> continueSending = 1;                 
    
//在这里,while循环条件是continueSending,表示当前的包如果没有发出去的话,continueSending就设为1,继续循环发送该包,这也是为什么Enet是可靠的UDP传输,因为它要确保每个连续的包都已经发出去并受到ACK。
//for循环在这里其实不用管,因为它是代表对端的个数,如果是一对一发送,for循环只循环一次,如果是一对多,则每次发送一个对端直到发完。而任何一个对端出现无法发送的情况都会使得Enet卡住不能发送。即Enet的重传机制。函数enet_protocol_send_acknowledgements是发送ack
    while (host -> continueSending)              
    for (host -> continueSending = 0,            
           currentPeer = host -> peers;          
         currentPeer < & host -> peers [host -> peerCount];                                                                                               
         ++ currentPeer)                         
    {                                                
        if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED || <span style="color:#009900;">//这个条件是在等待enet对端连接,如果一直没有连接则会一直循环continue</span>
            currentPeer -> state == ENET_PEER_STATE_ZOMBIE)
            continue;                            
                                                 
        host -> headerFlags = 0;                 
        host -> commandCount = 0;                
        host -> bufferCount = 1;                 
        host -> packetSize = sizeof (ENetProtocolHeader);
//这个是判断发送ack,如果ack不正确,enet_protocol_send_acknowledgements 会将continueSending置为1,从而让这个while一直循环发送该包。
       if (! enet_list_empty (& currentPeer -> acknowledgements))
            enet_protocol_send_acknowledgements (host, currentPeer);
                    
        if (checkForTimeouts != 0 &&
            ! enet_list_empty (& currentPeer -> sentReliableCommands) &&
            ENET_TIME_GREATER_EQUAL (host -> serviceTime, currentPeer -> nextTimeout) &&
            enet_protocol_check_timeouts (host, currentPeer, event) == 1)
        {           
            if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE)
              return 1;
            else    
              continue;
        }           
                    
        if ((enet_list_empty (& currentPeer -> outgoingReliableCommands) ||
              enet_protocol_send_reliable_outgoing_commands (host, currentPeer)) &&
            enet_list_empty (& currentPeer -> sentReliableCommands) &&
            ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval &&
            currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing))
        {           
            enet_peer_ping (currentPeer);
            enet_protocol_send_reliable_outgoing_commands (host, currentPeer);
        }           
                       
        if (! enet_list_empty (& currentPeer -> outgoingUnreliableCommands))
          enet_protocol_send_unreliable_outgoing_commands (host, currentPeer);
                    
        if (host -> commandCount == 0)  //commandCount初始值为0,循环几次后会被设置为1,然后继续下面的发送过程。 
            continue;

        if (currentPeer -> packetLossEpoch == 0)
          currentPeer -> packetLossEpoch = host -> serviceTime;
        else
        if (ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL//这个是传输结束后才会调用,计算总共的丢包比例。
            currentPeer -> packetsSent > 0)
        {   
           enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent;
            
//#ifdef ENET_DEBUG
           printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss /»
//#endif    
            
           currentPeer -> packetLossVariance -= currentPeer -> packetLossVariance / 4;
            
           if (packetLoss >= currentPeer -> packetLoss)
           {
              currentPeer -> packetLoss += (packetLoss - currentPeer -> packetLoss) / 8;
              currentPeer -> packetLossVariance += (packetLoss - currentPeer -> packetLoss) / 4;
           }
           else
           {
              currentPeer -> packetLoss -= (currentPeer -> packetLoss - packetLoss) / 8;
              currentPeer -> packetLossVariance += (currentPeer -> packetLoss - packetLoss) / 4;
           }
            
           currentPeer -> packetLossEpoch = host -> serviceTime;
           currentPeer -> packetsSent = 0;
           currentPeer -> packetsLost = 0;
        }   
            
        host -> buffers -> data = headerData;
        if (host -> headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)
        {   
            header -> sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF);
            
            host -> buffers -> dataLength = sizeof (ENetProtocolHeader);
        }   
        else                                                                                                                                                                                 
          host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime;
shouldCompress = 0;
        if (host -> compressor.context != NULL && host -> compressor.compress != NULL)
        {              
            size_t originalSize = host -> packetSize - sizeof(ENetProtocolHeader),           //填充buffers[1]
                   compressedSize = host -> compressor.compress (host -> compressor.context,
                                        & host -> buffers [1], host -> bufferCount - 1,
                                        originalSize,
                                        host -> packetData [1],
                                        originalSize);
            if (compressedSize > 0 && compressedSize < originalSize)
            {          
                host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED;
                shouldCompress = compressedSize;
#ifdef ENET_DEBUG_COMPRESS
                printf ("peer %u: compressed %u -> %u (%u%%)\n", currentPeer -> incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize);
#endif                 
            }          
        }              
                       
        if (currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID)
          host -> headerFlags |= currentPeer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT;
        header -> peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags);
        if (host -> checksum != NULL)
        {              
            enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength];
            * checksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0;
            host -> buffers -> dataLength += sizeof (enet_uint32);
            * checksum = host -> checksum (host -> buffers, host -> bufferCount);
        }              
                       
        if (shouldCompress > 0)
        {              
            host -> buffers [1].data = host -> packetData [1];
            host -> buffers [1].dataLength = shouldCompress;
            host -> bufferCount = 2;
        }              
                       
        currentPeer -> lastSendTime = host -> serviceTime;
                       
//真正的发包动作是socket
        sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount);
                                                                                                                                                                                             
        enet_protocol_remove_sent_unreliable_commands (currentPeer);
        if (sentLength < 0)
          return -1;   
                       
        host -> totalSentData += sentLength;
        host -> totalSentPackets ++;
    }                  
                       
    return 0;          
}              
           

在enet_socket_send()函数中,后两个参数是数据内容。host->buffers和host->bufferCount,都随着send()函数发送到对端。

而buffers是个数组(在host中),它们的长度分别为:

buffers[0] = 4  //header头信息
buffers[1] = 6
buffers[2] = 1024  //数据内容
buffers[3] = 12
           

继续阅读