Skip to content

interface

FreeBodyEngine.net.interface #

BYTE_ORDER = 'big' module-attribute #

LOCAL = '127.0.0.1' module-attribute #

NetworkAddress = tuple[str, int] module-attribute #

Contains the host and port.

ORDERED_BIT = 1 << 1 module-attribute #

RELIABLE_BIT = 1 << 0 module-attribute #

ACKPacket(channel, seq) #

Bases: Packet

A decoded ACK packet, confirming a DataPacket with sequence seq was received.

Args: channel: The logical channel the acknowledged packet was sent on. seq: The sequence number being acknowledged.

channel = channel instance-attribute #

seq = seq instance-attribute #

DataPacket(channel, flags, seq, length, payload, address) #

Bases: Packet

A decoded DATA packet carrying an application payload.

Args: channel: The logical channel this packet was sent/received on. flags: Bitfield of RELIABLE_BIT/ORDERED_BIT. seq: This packet's sequence number. length: Length of payload, in bytes. payload: The raw application payload. address: The (host, port) this packet came from/is going to.

address = address instance-attribute #

channel = channel instance-attribute #

flags = flags instance-attribute #

length = length instance-attribute #

payload = payload instance-attribute #

seq = seq instance-attribute #

NetworkInterface(port=7433, host=LOCAL, max_packet_size=4096, reliable_resend_threshold=0.3, sequence_duplicate_threshold=64) #

A basic UDP networking interface that inmplements TCP features to allow for both speed and reliability

Binds a non-blocking UDP socket at (host, port).

Parameters:

Name Type Description Default
port int

Local UDP port to bind.

7433
host str

Local address to bind.

LOCAL
max_packet_size int

Max bytes read per incoming packet in recieve_packet.

4096
reliable_resend_threshold float

Seconds to wait for an ACK before resending a reliable packet.

0.3
sequence_duplicate_threshold int

Sliding-window size passed to each peer's SequenceHandler - see SequenceHandler.threshold.

64

address = (self.host, self.port) instance-attribute #

host = host instance-attribute #

last_sequences = {} instance-attribute #

max_packet_size = max_packet_size instance-attribute #

ordered_buffers = {} instance-attribute #

packets = [] instance-attribute #

pending_reliable = {} instance-attribute #

port = port instance-attribute #

reliable_resend_threshold = reliable_resend_threshold instance-attribute #

seq_counter = 0 instance-attribute #

sequence_duplicate_threshold = sequence_duplicate_threshold instance-attribute #

socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) instance-attribute #

check_ordered_packet(packet, address) #

Runs packet through address's OrderedBuffer, creating one if this is the first ordered packet seen from address.

is_packet_duplicate(seq, address) #

Whether seq from address is a duplicate, creating a fresh SequenceHandler for address the first time it's seen.

poll_data() #

Drains every packet currently waiting on the socket, decoding each one and appending it to self.packets.

Duplicate reliable packets are still ACKed (the peer may not have gotten the first ACK) but not re-appended. Ordered packets are only appended once released in sequence by check_ordered_packet, so an early arrival can sit buffered rather than showing up in self.packets right away. A received ACK instead clears the matching entry from pending_reliable so it stops being resent.

process_reliable_packets() #

Resends any packet in pending_reliable that's been waiting longer than reliable_resend_threshold for its ACK.

recieve_packet() #

Reads one raw packet off the socket, returning (data, address), or (None, None) if the peer is unreachable (see send_packet).

send_ack_packet(channel, address, seq) #

Encodes and sends an ACK packet for sequence number seq to address.

send_data_packet(channel, address, payload, reliable=False, ordered=False) #

Encodes and sends a DATA packet to address, assigning it the next sequence number.

If reliable is set, the packet is also stashed in pending_reliable so process_reliable_packets will keep resending it until an ACK for its sequence number arrives.

Returns:

Type Description
int

The sequence number assigned to this packet.

send_packet(packet, address) #

Sends an already-encoded raw packet to address, silently dropping it if the peer is unreachable (see the ConnectionError comment below - UDP has no real "connection" to fail, so this can only mean a previous packet bounced).

update() #

Per-frame pump: reads and decodes any waiting packets, then resends any reliable packets that timed out waiting for an ACK.

OrderedBuffer() #

Per-peer reordering buffer for packets sent with ORDERED_BIT: holds packets that arrived out of order until the ones before them (by sequence number) show up, so check_packet releases them strictly in sequence.

Starts an empty buffer expecting sequence number 0 next.

next_seq = 0 instance-attribute #

packets = {} instance-attribute #

check_packet(packet) #

Buffers packet and returns every packet (including packet itself, if it was next) now releasable in sequence order.

get_releasable_packets() #

Pops and returns every buffered packet starting at next_seq that forms an unbroken run, advancing next_seq (wrapping at 16 bits) past them.

Packet(channel, type) #

Base class for a decoded packet - just enough shared state (channel, type) for both DataPacket and ACKPacket.

Args: channel: The logical channel this packet was sent/received on. type: The packet's PacketType.

channel = channel instance-attribute #

type = type instance-attribute #

PacketType #

Bases: Enum

The two wire-level packet kinds this protocol sends: DATA payloads and the ACKs that confirm a RELIABLE_BIT packet arrived.

ACK = auto() class-attribute instance-attribute #

DATA = auto() class-attribute instance-attribute #

SequenceHandler(threshold=64) #

Per-peer duplicate detection over a sliding window of recent sequence numbers, so a resent reliable packet (the sender never got the ACK) isn't processed twice.

threshold: How far behind the highest sequence number seen a sequence number can still be and be tracked/considered - both bounds the memory used and means anything older is just assumed to be a duplicate.

current_seq = -1 instance-attribute #

sequences = set() instance-attribute #

threshold = threshold instance-attribute #

is_duplicate(sequence) #

Whether sequence has already been seen, recording it if not.

A new highest sequence number is never a duplicate, and also prunes sequences of anything now older than threshold behind it. A sequence number older than threshold behind the current highest is always treated as a duplicate (it's outside the tracked window, so there's no way to tell) - otherwise it's a duplicate only if already in sequences.