/// <summary> /// Sends unsent messages and reads new messages from the wire /// </summary> protected override void Heartbeat() { double now = NetTime.Now; m_heartbeatCounter.Count(now); if (m_shutdownRequested) { PerformShutdown(m_shutdownReason); return; } if (m_connectRequested) { PerformConnect(); } // read messages from network BaseHeartbeat(now); if (m_serverConnection != null) { m_serverConnection.Heartbeat(now); // will send unsend messages etc. } }
/// <summary> /// Sends unsent messages and reads new messages from the wire /// </summary> public override void Heartbeat() { if (!m_isBound) { return; } double now = NetTime.Now; m_heartbeatCounter.Count(now); if (m_connectRequested) { PerformConnect(); } // read messages from network BaseHeartbeat(now); if (m_serverConnection != null) { m_serverConnection.Heartbeat(now); // will send unsend messages etc. } }
private void Heartbeat() { VerifyNetworkThread(); double dnow = NetTime.Now; float now = (float)dnow; double delta = dnow - m_lastHeartbeat; int maxCHBpS = 1250 - m_connections.Count; if (maxCHBpS < 250) { maxCHBpS = 250; } if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0) // max connection heartbeats/second max { m_frameCounter++; m_lastHeartbeat = dnow; // do handshake heartbeats if ((m_frameCounter % 3) == 0) { foreach (var kvp in m_handshakes) { NetConnection conn = kvp.Value as NetConnection; #if DEBUG // sanity check if (kvp.Key != kvp.Key) { LogWarning("Sanity fail! Connection in handshake list under wrong key!"); } #endif conn.UnconnectedHeartbeat(now); if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected) { #if DEBUG // sanity check if (conn.m_status == NetConnectionStatus.Disconnected && m_handshakes.ContainsKey(conn.RemoteEndPoint)) { LogWarning("Sanity fail! Handshakes list contained disconnected connection!"); m_handshakes.Remove(conn.RemoteEndPoint); } #endif break; // collection has been modified } } } #if DEBUG SendDelayedPackets(); #endif // update m_executeFlushSendQueue if (m_configuration.m_autoFlushSendQueue) { m_executeFlushSendQueue = true; } // do connection heartbeats lock (m_connections) { int ct = m_connections.Count; for (int i = 0; i < ct; ++i) { NetConnection conn = m_connections[i]; conn.Heartbeat(now, m_frameCounter); if (conn.m_status == NetConnectionStatus.Disconnected) { // // remove connection // m_connections.Remove(conn); m_connectionLookup.Remove(conn.RemoteEndPoint); break; // can't continue iteration here } } } m_executeFlushSendQueue = false; // send unsent unconnected messages NetTuple <IPEndPoint, NetOutgoingMessage> unsent; while (m_unsentUnconnectedMessages.TryDequeue(out unsent)) { NetOutgoingMessage om = unsent.Item2; bool connReset; int len = om.Encode(m_sendBuffer, 0, 0); SendPacket(len, unsent.Item1, 1, out connReset); Interlocked.Decrement(ref om.m_recyclingCount); if (om.m_recyclingCount <= 0) { Recycle(om); } } } // // read from socket // if (m_socket == null) { return; } if (!m_socket.Poll(1000, SelectMode.SelectRead)) // wait up to 1 ms for data to arrive { return; } //if (m_socket == null || m_socket.Available < 1) // return; // update now dnow = NetTime.Now; now = (float)dnow; do { int bytesReceived = 0; try { bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote); } catch (SocketException sx) { if (sx.SocketErrorCode == SocketError.ConnectionReset) { // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?! // So, what to do? LogWarning("ConnectionReset"); return; } LogWarning(sx.ToString()); return; } if (bytesReceived < NetConstants.HeaderByteSize) { return; } //LogVerbose("Received " + bytesReceived + " bytes"); IPEndPoint ipsender = (IPEndPoint)m_senderRemote; NetConnection sender = null; m_connectionLookup.TryGetValue(ipsender, out sender); // // parse packet into messages // int numMessages = 0; int ptr = 0; while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize) { // decode header // 8 bits - NetMessageType // 1 bit - Fragment? // 15 bits - Sequence number // 16 bits - Payload length in bits numMessages++; NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++]; byte low = m_receiveBuffer[ptr++]; byte high = m_receiveBuffer[ptr++]; bool isFragment = ((low & 1) == 1); ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7)); ushort payloadBitLength = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8)); int payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength); if (bytesReceived - ptr < payloadByteLength) { LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr)); return; } try { NetException.Assert(tp <NetMessageType.Unused1 || tp> NetMessageType.Unused29); if (tp >= NetMessageType.LibraryError) { if (sender != null) { sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength); } else { ReceivedUnconnectedLibraryMessage(dnow, ipsender, tp, ptr, payloadByteLength); } } else { if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData)) { return; // dropping unconnected message since it's not enabled } NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength); msg.m_isFragment = isFragment; msg.m_receiveTime = dnow; msg.m_sequenceNumber = sequenceNumber; msg.m_receivedMessageType = tp; msg.m_senderConnection = sender; msg.m_senderEndPoint = ipsender; msg.m_bitLength = payloadBitLength; Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength); if (sender != null) { if (tp == NetMessageType.Unconnected) { // We're connected; but we can still send unconnected messages to this peer msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; ReleaseMessage(msg); } else { // connected application (non-library) message sender.ReceivedMessage(msg); } } else { // at this point we know the message type is enabled // unconnected application (non-library) message msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData; ReleaseMessage(msg); } } } catch (Exception ex) { LogError("Packet parsing error: " + ex.Message + " from " + ipsender); } ptr += payloadByteLength; } m_statistics.PacketReceived(bytesReceived, numMessages); if (sender != null) { sender.m_statistics.PacketReceived(bytesReceived, numMessages); } } while (m_socket.Available > 0); }