Eigen protocoldecodering
Een privaat of intern socketprotocol vastgelegd dat de ingebouwde formaten niet herkennen, zodat je met niets anders dan een berg bytes blijft zitten? Met eigen decodering leer je de tool hoe die het moet lezen met een kort script: deel een doorlopende bytestroom op in afzonderlijke berichten, strip de protocolheader, decomprimeer waar nodig, en laat de rest over aan de automatische structurele herkenning van de tool.
Deze pagina is voor iedereen die zelf een decoder wil schrijven. Ze legt uit hoe je de functie schrijft, wanneer die wordt aangeroepen en wat de returnwaarde betekent.
1. Wat het is: een per-frame-decodeerhook
Section titled “1. Wat het is: een per-frame-decodeerhook”Je schrijft een decodeerhook, en de tool voedt hem de bytes van een verbinding en stelt daarbij steeds opnieuw dezelfde vraag: “Kun je, vanaf hier, één compleet bericht uitsnijden?” Je snijdt een bericht uit en meldt hoeveel bytes je hebt gebruikt; vervolgens vraagt de tool het opnieuw met de rest, en zo verder tot de stroom volledig is opgedeeld.
Als je ooit een accumulerende bytedecoder hebt geschreven in een netwerkframework, is het mentale model hetzelfde: gegeven een doorlopende bytestroom, bepaal je zelf de berichtgrenzen. Twee belangrijke afspraken:
- Je hoeft je niet druk te maken om de richting: de verzendstroom en de ontvangststroom van een verbinding lopen elk apart door je hook, en de tool labelt elk uitgesneden bericht automatisch met zijn richting. Je script hoeft alleen te bepalen “hoe te snijden.”
- Zodra iets is uitgesneden, hoef je het niet zelf weer te geven: elk bericht dat je naar buiten duwt, loopt opnieuw door de automatische herkenning. Als het protobuf, JSON of plist bevat, wordt dat verder ontleed tot een gestructureerde vorm. Jij bent alleen verantwoordelijk voor het framen, het strippen van headers en het decomprimeren.
2. De decode-functie: decode(buf, out)
Section titled “2. De decode-functie: decode(buf, out)”De hele decoder is één functie:
function decode(buf, out) { // buf: de bytestroom die momenteel wacht op ontleding; out: de outputverzamelaar; return: het aantal bytes dat deze keer is verbruikt}Wat de inputs, outputs en returnwaarde zijn
Section titled “Wat de inputs, outputs en returnwaarde zijn”buf (input): de bytestroom die wacht op ontleding
- Type:
ArrayBuffer. De inhoud bestaat uit alle resterende bytes “vanaf waar je de vorige keer bent gestopt met verbruiken, tot het huidige einde.” - Eigenschap
buf.byteLength: hoeveel bytes er op dit moment nog over zijn (dit kan bij elke aanroep groeien; hiermee bepaal je of er genoeg is om een bericht uit te snijden). - ⚠️ Het is een ruwe bytebuffer, geen
Uint8Array, dus je kunt bytes niet direct indexeren (buf[0]geeftundefined). Om bytes te lezen gebruik je de ingebouwde hulpfuncties uit sectie 3 (u8/u16be/sub…), of maak je zelf een view:new Uint8Array(buf),new DataView(buf).
out (output): de outputverzamelaar
- Type: een gewone array.
- Methode
out.push(berichtbytes): duw één bericht naar buiten; je kunt er meerdere pushen in één aanroep. - “Berichtbytes” kunnen zijn: een
ArrayBufferteruggegeven door een ingebouwde hulpfunctie (zoalssub(...),gunzip(...)), of een string. Andere types worden genegeerd.
Returnwaarde: hoeveel bytes je hebt verbruikt
- Type: geheel getal (
number), het aantal bytes dat je hebt gebruikt vanaf het begin vanbuf. > 0: je hebt zoveel bytes van de voorkant opgegeten en er een bericht uit gesneden → de tool verwijdert ze en roept je opnieuw aan met de rest.0/ geenreturn/ negatief getal: betekent “er zit nog geen compleet bericht aan de voorkant” of “er kan niets meer worden uitgesneden” → de tool stopt de lus en toont de resterende bytes als ruwe data.- De returnwaarde wordt automatisch beperkt tot de bufferlengte (om overschrijdingen te voorkomen), maar geef alsjeblieft het werkelijke aantal bytes terug dat je daadwerkelijk hebt gebruikt.
Wanneer het wordt aangeroepen (levenscyclus)
Section titled “Wanneer het wordt aangeroepen (levenscyclus)”- De tool doorloopt één keer de verzendstroom en één keer de ontvangststroom van een verbinding. Bij elke doorloop wordt
decodein een lus aangeroepen: elke keer krijg je de resterende onverbruikte bytes, snijd je één bericht uit en geef je terug hoeveel er zijn verbruikt, enzovoort tot je 0 teruggeeft. - Een bericht verschijnt pas zodra het verbruik ervan is bevestigd: het bericht dat je pusht, verschijnt pas zodra je ook > 0 teruggeeft. Als je pusht maar 0 teruggeeft, stopt de lus en wordt de push weggegooid, dus het pushen van een bericht moet altijd gepaard gaan met het teruggeven van hoeveel bytes het kostte.
- Nadat de lus is beëindigd, gaan resterende onverbruikte bytes aan het einde niet verloren; ze worden getoond als één stuk ruwe data (bijvoorbeeld de tweede helft van een onvolledig bericht).
Status en idempotentie
Section titled “Status en idempotentie”- Elke stroom (richting) krijgt een aparte, gloednieuwe scriptomgeving; de verzendstroom en de ontvangststroom lekken nooit in elkaar over.
- Om status tussen aanroepen te bewaren (een teller, het type van het vorige bericht, enzovoort), declareer je de variabelen buiten
decode. Ze blijven bestaan tussen aanroepen binnen dezelfde stroom, en worden gereset wanneer de richting verandert of je opnieuw decodeert. - Decoderen werkt op al vastgelegde data, en kan herhaaldelijk opnieuw worden uitgevoerd: bewerk het script, sla op en klik opnieuw om dezelfde verbinding met de nieuwe regels opnieuw te decoderen.
Fouten breken niets
Section titled “Fouten breken niets”- Als het script een uitzondering gooit of een enkele run te lang duurt, wordt dat behandeld als “deze keer niets verbruikt,” worden de resterende bytes getoond als ruwe data, en blijft het vastleggen gewoon doorlopen zonder dataverlies.
- Met andere woorden, het ergste dat een kapot script kan doen is niet decoderen en je met ruwe bytes achterlaten; het laat de verbinding niet crashen. Bewerk vrijuit.
- En fouten worden niet weggeslikt: uitzonderingen en time-outs worden getoond in het debugoutput-paneel boven de resultaten (zie sectie 5), gelabeld met of ze afkomstig zijn van de verzendstroom
↑of de ontvangststroom↓. Volg ze recht naar de oplossing.
3. Ingebouwde hulpfuncties (direct beschikbaar in het script)
Section titled “3. Ingebouwde hulpfuncties (direct beschikbaar in het script)”De veelvoorkomende taken, bytes lezen, gehele getallen lezen, omzetten naar tekst en decomprimeren, zijn allemaal ingebouwd, zodat je ze niet opnieuw hoeft uit te vinden:
| Categorie | Signatuur | Beschrijving |
|---|---|---|
| Sub-slice nemen | sub(buf, off[, len]) |
Snijd vanaf off (laat len weg om tot het einde te gaan), geeft ArrayBuffer terug |
| Geheel getal lezen | u8(buf, off) / u16be / u16le / u32be / u32le (buf, off) |
Lees unsigned gehele getallen in big-endian / little-endian |
| Omzetten naar tekst | hex(buf) / ascii(buf) |
Omzetten naar een hexstring / lezen als tekst |
| Compressie detecteren | gzipMagic(buf) |
Of het gzip is (geeft een boolean terug) |
| Decomprimeren | gunzip / inflate / unzstd / lz4dtx (buf) |
Decomprimeren; als het niet lukt, wordt de input ongewijzigd teruggegeven zonder foutmelding |
| Debug | log(...args) / console.log(...args) |
Printen naar het debugpaneel (zie sectie 5) |
De standaard byte-lees-/schrijfmogelijkheden (DataView, Uint8Array, enz.) zijn ook direct bruikbaar.
4. Voorbeelden
Section titled “4. Voorbeelden”① Lengteprefix [4-byte big-endian lengte][payload], de meest voorkomende vorm van een privaat protocol:
function decode(buf, out) { if (buf.byteLength < 4) return 0 // de lengteheader is nog niet volledig binnen, wachten const total = 4 + u32be(buf, 0) // heel bericht = 4-byte header + payload if (buf.byteLength < total) return 0 // het hele bericht is nog niet volledig binnen, wachten out.push(sub(buf, 4, total - 4)) // strip de header, geef de payload door aan automatische herkenning return total // verbruik dit bericht, ga verder met het volgende uitsnijden}② Op scheidingsteken / per regel, frames uitsnijden op een markering zoals een newline:
function decode(buf, out) { const i = ascii(buf).indexOf('\n') if (i < 0) return 0 // nog geen newline, wachten out.push(sub(buf, 0, i)) // duw deze regel naar buiten (zonder de newline) return i + 1 // verbruik de newline ook mee}③ Alles in één keer verwerken, waarbij de hele stroom als één bericht wordt behandeld, bijvoorbeeld door het geheel te decomprimeren:
function decode(buf, out) { out.push(gzipMagic(buf) ? gunzip(buf) : buf) // als het gzip is, pak het dan uit return buf.byteLength // verbruik alles, de lus eindigt meteen}④ Verdelen naar type, met een typeveld in de header en verschillende afhandeling per type:
function decode(buf, out) { if (buf.byteLength < 4) return 0 const total = 4 + u32be(buf, 0) if (buf.byteLength < total) return 0 const type = u8(buf, 4) // het eerste byte is het berichttype const body = sub(buf, 5, total - 5) out.push(type === 2 ? gunzip(body) : body) // type 2 is gecomprimeerd return total}De editor heeft kant-en-klare sjablonen voor al deze patronen; voeg er een in, pas een paar getallen aan, en het draait.

5. Hoe je het gebruikt, hoe je het debugt
Section titled “5. Hoe je het gebruikt, hoe je het debugt”- Schrijven en opslaan: maak, benoem en sla op in de decoder-editor; voeg een sjabloon in om te beginnen, met de ingebouwde functies in een snelle referentie binnen handbereik.
- Toepassen: klik voor een verbinding waar je niets van begrijpt met rechts en kies “Decoderen als” → je decoder, en het verzend- en ontvangstverkeer van de hele verbinding wordt meteen opgedeeld en getoond volgens jouw regels.
- Debuggen en variabelen inspecteren: gebruik binnen
decodelog(...)ofconsole.log(...)om elke waarde te printen: aantallen bytes, typevelden,hex(sub(buf, 0, 8)), enzovoort. De output verschijnt in het paneel “Debugoutput” boven de resultaten van “Decoderen als”, elke regel gelabeld met of hij afkomstig is van de verzendstroom↑of de ontvangststroom↓. Scriptfouten en time-outs verschijnen in hetzelfde paneel, ook gelabeld met richting. Print en lokaliseer op deze manier; het is veel sneller dan blindelings bewerken.De sandbox heeft geen volledige browser-/Node-
console; alleenconsole.logen het equivalentelogzijn aangesloten op dit paneel.TextDecoder,fetch,setTimeouten dergelijke zijn niet beschikbaar. Om bytes als tekst te lezen, gebruikascii(buf). - Bewerken en het live zien: geen nieuwe capture nodig. Sla je script op, klik opnieuw op “Decoderen als”, en dezelfde verbinding wordt ter plekke opnieuw gedecodeerd met de nieuwe regels. Itereer tot het precies zo snijdt als je wilt.
- Verder naar de structuur: elk gedecodeerd stuk wordt teruggegeven aan de automatische herkenning, zodat protobuf, JSON en plist verder worden ontleed tot een gestructureerde vorm, te bekijken via de meerdere weergaven in Inspecteren en decoderen.
- Decoders kunnen worden benoemd en bewaard als een lijst, op elk moment toe te voegen, te bewerken of te verwijderen.
6. Wanneer je het gebruikt
Section titled “6. Wanneer je het gebruikt”- Wanneer je een intern of privaat socketprotocol vastlegt (een veelvoorkomende vorm is lengteprefix + protobuf / JSON / binair) dat de ingebouwde formaten niet herkennen, schrijf je een decoder om het op te delen en te herstellen tot een leesbare structuur.
- Wanneer je een stuk bytes, verpakt in een eigen header of gecomprimeerd, weer wilt terugbrengen naar leesbare inhoud.
7. API-referentie
Section titled “7. API-referentie”Een geconsolideerde snelle referentie: het decode-toegangspunt, de ingebouwde hulpfuncties en de runtimeomgeving. Elke functie die buf accepteert, accepteert zowel een ArrayBuffer als een string.
Decode-toegangspunt
Section titled “Decode-toegangspunt”decode(buf, out) → number| Doel | Het enige toegangspunt van de decoder, moet worden geïmplementeerd. Snijd berichten uit vanaf het begin van buf, push ze naar out, en geef het aantal deze keer verbruikte bytes terug. |
buf |
ArrayBuffer, de resterende bytestroom die wacht op ontleding. Gebruik buf.byteLength voor de lengte; je kunt bytes niet indexeren, gebruik de hulpfuncties hieronder of new DataView(buf) / new Uint8Array(buf). |
out |
Array, de outputverzamelaar. out.push(bytes) duwt één bericht naar buiten (bytes is een ArrayBuffer of een string; andere types worden genegeerd); je kunt er meerdere tegelijk pushen. |
| Return | number, de vanaf het begin van buf verbruikte bytes. > 0 gaat door; 0 / negatief / geen return → stoppen, en de resterende bytes worden getoond als ruwe data. |
| Aanroepconventie | Doorloop één keer de verzendstroom en één keer de ontvangststroom van de verbinding; elke doorloop roept herhaaldelijk aan, waarbij elke keer de resterende onverbruikte bytes worden meegegeven, tot je 0 teruggeeft. |
Ingebouwde hulpfuncties
Section titled “Ingebouwde hulpfuncties”Sub-slice nemen
| Signatuur | Retourneert | Beschrijving |
|---|---|---|
sub(buf, off) |
ArrayBuffer |
Snijd vanaf off tot het einde |
sub(buf, off, len) |
ArrayBuffer |
Snijd len bytes vanaf off; een off / len buiten bereik wordt automatisch beperkt, geen fout |
Geheel getal lezen (unsigned; geeft 0 terug wanneer off buiten bereik ligt)
| Signatuur | Retourneert | Beschrijving |
|---|---|---|
u8(buf, off) |
number |
Lees 1 byte |
u16be(buf, off) / u16le(buf, off) |
number |
Lees 2 bytes, big-endian / little-endian |
u32be(buf, off) / u32le(buf, off) |
number |
Lees 4 bytes, big-endian / little-endian |
Omzetten naar tekst
| Signatuur | Retourneert | Beschrijving |
|---|---|---|
hex(buf) |
string |
Omzetten naar hexadecimaal in kleine letters |
ascii(buf) |
string |
Uitlezen als tekst (geschikt voor ASCII-/tekstinhoud) |
Compressie / decompressie (geeft de input ongewijzigd terug als decomprimeren niet lukt; enkele decompressie is begrensd op ongeveer 16 MB)
| Signatuur | Retourneert | Beschrijving |
|---|---|---|
gzipMagic(buf) |
boolean |
Of het begint met het gzip magic number |
gunzip(buf) |
ArrayBuffer |
gzip-decompressie |
inflate(buf) |
ArrayBuffer |
zlib-/deflate-decompressie |
unzstd(buf) |
ArrayBuffer |
zstd-decompressie |
lz4dtx(buf) |
ArrayBuffer |
Blok-LZ4-streamdecompressie |
Debug
| Signatuur | Retourneert | Beschrijving |
|---|---|---|
log(...args) |
(geen) | Voeg de argumenten samen tot één regel en print naar het paneel “Debugoutput”; een ArrayBuffer wordt getoond in hexadecimaal |
console.log(...args) |
(geen) | Hetzelfde als log (handig voor wie gewend is aan console.log) |
Runtimeomgeving
Section titled “Runtimeomgeving”- Standaard JavaScript: gangbare ingebouwde objecten zoals
ArrayBuffer, typed arrays (Uint8Array, enz.),DataView,JSON,Math,RegExp,Datezijn allemaal beschikbaar; wanneer je lager-niveau byte-lees-/schrijftoegang nodig hebt, staannew DataView(buf)/new Uint8Array(buf)klaar. - Debug:
log(...)/console.log(...)printen naar het paneel “Debugoutput”; scriptfouten en time-outs worden daar ook geprint, gelabeld met of ze afkomstig zijn van de verzendstroom↑of de ontvangststroom↓. - Niet beschikbaar zijn de overige browser-/Node-specifieke mogelijkheden:
console-methoden anders danlog,TextDecoder/TextEncoder,fetch,setTimeout,require, enz. zijn allemaal niet beschikbaar. Om bytes als tekst te lezen, gebruikascii(buf). - Elke
decode-aanroep heeft een uitvoeringstijdlimiet: een oneindige lus of een time-out wordt onderbroken en behandeld als “niets verbruikt,” zodat de tool nooit vastloopt.
Terug naar Proxy-capture · Gerelateerd: Inspecteren en decoderen · Lokale NIC-capture