One of the reasons I was asking this is because if you have a small window size for datagrams, if you have high enough packet loss it's possible to have all packets dropped or all acks dropped, but then again trying to salvage that situation is just going to degrade the system with a lot bloat for super high packet loss situations anyway so might aswell just drop the client.
Yup. You don't really want troublesome clients in your game anyway.
BTW the ack / sqn encoding is relative to your maximum window size. Often SQN / ACKs are not absolute (32 / 64 bit numbers), but relative. Saves a few bits.
bool sqn_greater(unsigned short a, unsigned short b) { return (a > b) && (a <= b + 0x1000) || (b > a) && (b > a + (0x1000); }
bool short sqn_greater_equal(unsigned short a, unsigned short b) { return (a == b) || sqn_greater(a, b); }
unsigned short sqn_add(unsigned short a, unsigned short b) { return (a + b); }
unsigned short sqn_diff(unsigned short a, unsigned short b) { ASSERT(sqn_greater_equal(a, b)); return (a - b); }
The maximum window size here is 32768 (half the range of a unsigned short, or 16 bits). If your client stray outside your window, or your message buffer is greater than 32KB, then you either kick the client (harsh!), or keep resending the data in the window until it's acknowledged before you can send some new data. If you end up in that situation, you may end up filling up your message buffer anyway, if you push new messages faster than the client can acknowledge them.
Coincidently, there is also a throughput limit associated with high latencies (> 1000 ms).
And when you come to resend data, you obviously want to reduce your throughput to reduce packet drop and choking your bandwidth, or spread the bandwidth available among multiple clients, which is basically flow control. There are various algorithms based on latency, and artificial bandwidth throttling that you can apply.
BTW, you don't have to use 16 bits, can be anything depending on what works for you. You can limit the window to say, 10 bits, which means you will start resending data if the client hasn't acknowledged the past 1024 bytes (or whatever atomic unit you choose).