public GameClient(string address, int port) { _udp = new UdpClient(0) { Client = { Blocking = false } }; _target = new IPEndPoint(IPAddress.Parse(address), port); _server = new NetworkConnection(_udp, _target); _server.MessageReceived += (fromAddr, message) => MessageReceived?.Invoke(fromAddr, message); _server.ClientDisconnected += (fromAddr) => ServerDisconnected?.Invoke(fromAddr); _server.MessageAcked += (fromAddr, message) => MessageAcked?.Invoke(fromAddr, message); _server.MessageLost += (fromAddr, message) => MessageLost?.Invoke(fromAddr, message); _reliable = new ReliableConnection(_server); _reliable.ReliableMessageRecieved += (fromAddr, message) => ReliableMessageReceived?.Invoke(fromAddr, message); }
private void HandleNewClientConnection(IPEndPoint clientAddr) { _clients[clientAddr] = new NetworkConnection(_udp, clientAddr); _clients[clientAddr].MessageReceived += (fromAddr, message) => MessageReceived?.Invoke(fromAddr, message); _clients[clientAddr].ClientDisconnected += (fromAddr) => { _clients.Remove(fromAddr); _reliableClients.Remove(fromAddr); ClientDisconnected?.Invoke(fromAddr); }; _clients[clientAddr].MessageAcked += (fromAddr, message) => MessageAcked?.Invoke(fromAddr, message); _clients[clientAddr].MessageLost += (fromAddr, message) => MessageLost?.Invoke(fromAddr, message); _reliableClients[clientAddr] = new ReliableConnection(_clients[clientAddr]); _reliableClients[clientAddr].ReliableMessageRecieved += (fromAddr, message) => ReliableMessageReceived?.Invoke(fromAddr, message); ClientConnected?.Invoke(clientAddr); }
public void EnqueueReceive(IPEndPoint fromAddr, byte[] packet) { // Reset timeout accumulator - we just got a packet. _timeoutAccumulator = 0; _connected = true; // Read the sequence, ack and ack bitfield. In this case, the sequence // is the remote connection's sequence - and thus the sequence number // we will be acknowledging. Meanwhile the acks are for the messages // that we sent out. var remoteSeq = BitConverter.ToUInt16(packet, 0); var remoteAck = BitConverter.ToUInt16(packet, sizeof(ushort)); var remoteAckBitfield = BitConverter.ToUInt32(packet, sizeof(ushort) * 2); /******* * * WARNING! This code does not handle sequence number overflow. Refer to * https://web.archive.org/web/20181107181433/https://gafferongames.com/post/reliability_ordering_and_congestion_avoidance_over_udp/#handling-sequence-number-wrap-around * for information on how to handle this. * ********/ // Update our acknowledgement of packets the remote machine sent. var lastGot = _ackSeq; var nowGot = remoteSeq; if (nowGot == lastGot) { // Remote acknowledgement is in the same state, nothing to do. } else { // We need to move the acknowledgement of the packet we last got // into the bitfield first. _ackBitField <<= 1; _ackBitField |= 0x1; // Shift bitfield across for all the packets we lost in between. if (nowGot - lastGot > 1) { _ackBitField <<= (nowGot - lastGot) - 1; } } _ackSeq = remoteSeq; // Read the acknowledgement data from the remote machine about packets we sent. if (_pendingSendAcks.ContainsKey(remoteAck)) { // If it's in the ack field, the remote machine received it. foreach (var message in _pendingSendAcks[remoteAck]) { MessageAcked?.Invoke(_target, message); } _pendingSendAcks.Remove(remoteAck); } for (var i = 0; i < sizeof(uint); i++) { var seqInBitfield = (ushort)(remoteAck - i - 1); var isAcked = ((remoteAckBitfield >> i) & 0x1) == 0x1; if (_pendingSendAcks.ContainsKey(seqInBitfield)) { foreach (var message in _pendingSendAcks[seqInBitfield]) { if (isAcked) { MessageAcked?.Invoke(_target, message); } else { MessageLost?.Invoke(_target, message); } } } _pendingSendAcks.Remove(seqInBitfield); } // Take the raw packet and split it out into the messages it contains. var offset = PACKET_HEADER_SIZE_BYTES; while (offset < packet.Length) { var len = BitConverter.ToUInt16(packet, offset); offset += 2; var message = new byte[len]; Array.Copy(packet, offset, message, 0, len); offset += len; MessageReceived?.Invoke(fromAddr, message); } }