public GameServer(int port, MessageReceived onReceive, ClientConnected onClientConnected, ClientDisconnected onClientDisconnected, MessageAcked onAck, MessageLost onLost) { _udp = new UdpClient(port) { Client = { Blocking = false } }; _clients = new Dictionary <IPEndPoint, NetworkConnection>(); _onReceive = onReceive; _onClientConnected = onClientConnected; _onClientDisconnected = onClientDisconnected; _onAck = onAck; _onLost = onLost; }
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 NetworkConnection(UdpClient udp, IPEndPoint target, MessageReceived onReceive, ClientDisconnected onDisconnect, MessageAcked onAck, MessageLost onLost) { _udp = udp; _target = target; _sendQueue = new Queue <byte[]>(); _onReceive = onReceive; _onAck = onAck; _onLost = onLost; _onDisconnect = onDisconnect; _connected = true; _timeoutAccumulator = 0; _sendSeq = 0; _ackSeq = 0; _ackBitField = 0; _sendQueueSize = PACKET_HEADER_SIZE_BYTES; _pendingSendAcks = new Dictionary <ushort, byte[][]>(); }
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); } }
public GameClient(string address, int port, MessageReceived onReceive, ClientDisconnected onTimeout, MessageAcked onAck, MessageLost onLost) { _udp = new UdpClient(0) { Client = { Blocking = false } }; _target = new IPEndPoint(IPAddress.Parse(address), port); _server = new NetworkConnection(_udp, _target, onReceive, onTimeout, onAck, onLost); }