标签:
Features:
channels 这个设计目前我理解的为了进行负载均衡, 比如 client -》 zoneconnect -》 zoneserver
如果此时 client zoneconnect 1 num ,zoneconnect zoneserver 2 num , 1 num 之间通信发生了拥塞,此时通过拥塞控制,减少发包频率,如果
2 num 也在发包呢? 然而此时的 1 num 已经发生了拥塞 ,那么我们的所需要发送的数据包,只有异步等待 1 num发送 为了解决这个问题的延迟,并减少对数据包的限制,使用多通道独立的进行发送,因此此时一个通道的数据包传送状态不会影响其他通道的包传送 。
如果默认为0 则是禁止开启流量控制,和拥塞控制。(参考 tcpv2 内核源码)
To combat
this latency and reduce the ordering restrictions on packets, ENet provides multiple channels of communication over a given connection. Each channel is independently sequenced, and so the delivery status of a packet in one channel will not stall the delivery
of other packets in another channel.
ENetHost *
enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth,enet_uint32 outgoingBandwidth)
{
ENetHost * host; //服务器本端 一个全局变量存储数据
ENetPeer * currentPeer;//当前客户端就是一个peer
//ENET_PROTOCOL_MAXIMUM_PEER_ID
//
if( peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID )
return NULL;
host = (ENetHost *) enet_malloc (sizeof (ENetHost));
if (host == NULL)
return NULL;
memset(host, 0, sizeof (ENetHost));
host ->peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer));
if (host ->peers == NULL)
{
enet_free (host);
return NULL;
}
memset (host ->peers, 0, peerCount * sizeof (ENetPeer));
host ->socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
if (host ->socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host ->socket, address) < 0))
{
if (host ->socket != ENET_SOCKET_NULL)
enet_socket_destroy (host ->socket);
enet_free (host ->peers);
enet_free (host);
return NULL;
}
enet_socket_set_option (host ->socket, ENET_SOCKOPT_NONBLOCK, 1); //设置非阻塞
enet_socket_set_option (host ->socket, ENET_SOCKOPT_BROADCAST, 1);//设置广播
enet_socket_set_option (host ->socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); //设置socket 接受缓冲区
enet_socket_set_option (host ->socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);//设置socket发送缓冲区
if (address != NULL && enet_socket_get_address (host ->socket, & host -> address) < 0) // 绑定socket 设置地址
host -> address = * address;
if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
else
if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
host ->randomSeed = (enet_uint32) (size_t) host;
host ->randomSeed += enet_host_random_seed ();
host ->randomSeed = (host ->randomSeed << 16) | (host ->randomSeed >> 16);
host ->channelLimit = channelLimit;
host ->incomingBandwidth = incomingBandwidth;
host ->outgoingBandwidth = outgoingBandwidth;
host ->bandwidthThrottleEpoch = 0;
host ->recalculateBandwidthLimits = 0;
host ->mtu = ENET_HOST_DEFAULT_MTU; //通信最大包限制, 本身自带分包发送。
host ->peerCount = peerCount;
host ->commandCount = 0;
host ->bufferCount = 0;
host ->checksum = NULL;
host ->receivedAddress.host = ENET_HOST_ANY;
host ->receivedAddress.port = 0;
host ->receivedData = NULL;
host ->receivedDataLength = 0;
host ->totalSentData = 0;
host ->totalSentPackets = 0;
host ->totalReceivedData = 0;
host ->totalReceivedPackets = 0;
host ->connectedPeers = 0;
host ->bandwidthLimitedPeers = 0;
host ->duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID;
host ->maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE;
host ->maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA;
host ->compressor.context = NULL; // 这里开启压缩包算法
host ->compressor.compress = NULL;
host ->compressor.decompress = NULL;
host ->compressor.destroy = NULL;
host ->intercept = NULL;
enet_list_clear (& host ->dispatchQueue); //双向链表 每次必须clear 使得双指针指向头节点
for (currentPeer = host ->peers;
currentPeer < & host ->peers [host -> peerCount];
++ currentPeer)
{
currentPeer ->host = host;
currentPeer ->incomingPeerID = currentPeer - host ->peers;
currentPeer ->outgoingSessionID = currentPeer ->incomingSessionID = 0xFF;
currentPeer ->data = NULL;
enet_list_clear (& currentPeer ->acknowledgements);
enet_list_clear (& currentPeer ->sentReliableCommands);
enet_list_clear (& currentPeer ->sentUnreliableCommands);
enet_list_clear (& currentPeer ->outgoingReliableCommands);
enet_list_clear (& currentPeer ->outgoingUnreliableCommands);
enet_list_clear (& currentPeer ->dispatchedCommands);
enet_peer_reset (currentPeer);
}
return host;
}
2.
/**
Forcefully disconnects a peer.
@param peer peer to forcefully disconnect
@remarks The foreign host represented by the peer is not notified of the disconnection and will timeout
on its connection to the local host.
*/
void
enet_peer_reset (ENetPeer * peer)
{
enet_peer_on_disconnect (peer);
peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID;
peer -> connectID = 0;
peer -> state = ENET_PEER_STATE_DISCONNECTED;
peer -> incomingBandwidth = 0;
peer -> outgoingBandwidth = 0;
peer -> incomingBandwidthThrottleEpoch = 0;
peer -> outgoingBandwidthThrottleEpoch = 0;
peer -> incomingDataTotal = 0;
peer -> outgoingDataTotal = 0;
peer -> lastSendTime = 0;
peer -> lastReceiveTime = 0;
peer -> nextTimeout = 0; 客户端下次超时时间
peer -> earliestTimeout = 0; 最早的超时时间
peer -> packetLossEpoch = 0;
peer -> packetsSent = 0;
peer -> packetsLost = 0;
peer -> packetLoss = 0;
peer -> packetLossVariance = 0;
peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE;
peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE;
peer -> packetThrottleCounter = 0;
peer -> packetThrottleEpoch = 0;
peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION;
peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION;
peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL;
peer -> pingInterval = ENET_PEER_PING_INTERVAL; 心跳检测时间
peer -> timeoutLimit = ENET_PEER_TIMEOUT_LIMIT;
peer -> timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM;
peer -> timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM; 最大超时时间 如果没有收到对端的ack确认,会一直重传,至道最大超时,并且踢掉玩家
peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
peer -> lastRoundTripTimeVariance = 0;
peer -> highestRoundTripTimeVariance = 0;
peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; 客户端和服务器通信往返时间设置,用于判断是否超时
peer -> roundTripTimeVariance = 0;
peer -> mtu = peer -> host -> mtu;
peer -> reliableDataInTransit = 0;
peer -> outgoingReliableSequenceNumber = 0;
peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; 滑动窗口大小
peer -> incomingUnsequencedGroup = 0;
peer -> outgoingUnsequencedGroup = 0;
peer -> eventData = 0;
peer -> totalWaitingData = 0;
memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow));
enet_peer_reset_queues (peer);
}
3.
void
enet_peer_reset_queues (ENetPeer * peer)
{
ENetChannel * channel;
if (peer -> needsDispatch)
{
enet_list_remove (& peer -> dispatchList); 收到收到的数据包都会加入到调度队列
peer -> needsDispatch = 0;
}
while (! enet_list_empty (& peer -> acknowledgements)) 对端确认协议
enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements)));
enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands); 可靠数据包协议 (每次发送send包后,需要存储到这个双向链表,目的在于存储,用于超时重传,只有收到ack确认,才会删除)
enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands); 不可靠数据包协议
enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands); 发送数据所有都会优先加入到 进来的可靠数据包协议 然后send后,又会加入到peer -> sentReliableCommands 如果检测超时,又会从新回到peer -> outgoingReliableCommands
enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands);
enet_peer_reset_incoming_commands (& peer -> dispatchedCommands); 调度协议
if (peer -> channels != NULL && peer -> channelCount > 0) 初始化通道
{
for (channel = peer -> channels;
channel < & peer -> channels [peer -> channelCount];
++ channel)
{
enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands);
enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands);
}
enet_free (peer -> channels);
}
peer -> channels = NULL;
peer -> channelCount = 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/a474711079/article/details/46836495