예제 #1
0
 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);
 }
예제 #2
0
 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);
 }
예제 #3
0
        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);
            }
        }