Hinweis: Dies ist eine Erklärung und ein Pseudocode zur Implementierung eines sehr einfachen Servers, der eingehende und ausgehende WebSocket-Nachrichten gemäß dem endgültigen Rahmenformat verarbeiten kann. Der Handshake-Prozess ist nicht enthalten. Darüber hinaus wurde diese Antwort zu Bildungszwecken gegeben; Es handelt sich nicht um eine Implementierung mit vollem Funktionsumfang.
Spezifikation (RFC 6455)
Nachrichten senden
(Mit anderen Worten, Server → Browser)
Die von Ihnen gesendeten Frames müssen gemäß dem WebSocket-Framing-Format formatiert sein. Zum Senden von Nachrichten lautet dieses Format wie folgt:
- ein Byte, das den Datentyp enthält (und einige zusätzliche Informationen, die für einen einfachen Server nicht verfügbar sind)
- ein Byte, das die Länge enthält
- entweder zwei oder acht Bytes, wenn die Länge nicht in das zweite Byte passt (das zweite Byte ist dann ein Code, der angibt, wie viele Bytes für die Länge verwendet werden)
- die tatsächlichen (Roh-) Daten
Das erste Byte ist 1000 0001
(oder 129
) für einen Textrahmen.
Für das zweite Byte ist das erste Bit gesetzt, 0
da die Daten nicht codiert werden (die Codierung vom Server zum Client ist nicht obligatorisch).
Es ist notwendig, die Länge der Rohdaten zu bestimmen, um die Längenbytes korrekt zu senden:
- Wenn
0 <= length <= 125
, brauchen Sie keine zusätzlichen Bytes
- Wenn
126 <= length <= 65535
Sie zwei zusätzliche Bytes benötigen, ist das zweite Byte126
- Wenn
length >= 65536
, benötigen Sie acht zusätzliche Bytes, und das zweite Byte ist127
Die Länge muss in separate Bytes aufgeteilt werden, was bedeutet, dass Sie die Bitverschiebung nach rechts (mit einer Menge von acht Bits) durchführen und dann nur die letzten acht Bits beibehalten müssen AND 1111 1111
(dh 255
).
Nach den Längenbytes folgen die Rohdaten.
Dies führt zu folgendem Pseudocode:
bytesFormatted[0] = 129
indexStartRawData = -1 // it doesn't matter what value is
// set here - it will be set now:
if bytesRaw.length <= 125
bytesFormatted[1] = bytesRaw.length
indexStartRawData = 2
else if bytesRaw.length >= 126 and bytesRaw.length <= 65535
bytesFormatted[1] = 126
bytesFormatted[2] = ( bytesRaw.length >> 8 ) AND 255
bytesFormatted[3] = ( bytesRaw.length ) AND 255
indexStartRawData = 4
else
bytesFormatted[1] = 127
bytesFormatted[2] = ( bytesRaw.length >> 56 ) AND 255
bytesFormatted[3] = ( bytesRaw.length >> 48 ) AND 255
bytesFormatted[4] = ( bytesRaw.length >> 40 ) AND 255
bytesFormatted[5] = ( bytesRaw.length >> 32 ) AND 255
bytesFormatted[6] = ( bytesRaw.length >> 24 ) AND 255
bytesFormatted[7] = ( bytesRaw.length >> 16 ) AND 255
bytesFormatted[8] = ( bytesRaw.length >> 8 ) AND 255
bytesFormatted[9] = ( bytesRaw.length ) AND 255
indexStartRawData = 10
// put raw data at the correct index
bytesFormatted.put(bytesRaw, indexStartRawData)
// now send bytesFormatted (e.g. write it to the socket stream)
Nachrichten empfangen
(Mit anderen Worten, Browser → Server)
Die Frames, die Sie erhalten, haben das folgende Format:
- Ein Byte, das den Datentyp enthält
- ein Byte, das die Länge enthält
- entweder zwei oder acht zusätzliche Bytes, wenn die Länge nicht in das zweite Byte passt
- vier Bytes, die die Masken sind (= Decodierungsschlüssel)
- die tatsächlichen Daten
Das erste Byte spielt normalerweise keine Rolle - wenn Sie nur Text senden, verwenden Sie nur den Texttyp. Es wird 1000 0001
(oder 129
) in diesem Fall sein.
Das zweite Byte und die zusätzlichen zwei oder acht Bytes müssen analysiert werden, da Sie wissen müssen, wie viele Bytes für die Länge verwendet werden (Sie müssen wissen, wo die realen Daten beginnen). Die Länge selbst ist normalerweise nicht erforderlich, da Sie die Daten bereits haben.
Das erste Bit des zweiten Bytes ist immer, 1
was bedeutet, dass die Daten maskiert (= codiert) sind. Nachrichten vom Client an den Server werden immer maskiert. Sie müssen das erste Bit entfernen, indem Sie dies tun secondByte AND 0111 1111
. Es gibt zwei Fälle, in denen das resultierende Byte nicht die Länge darstellt, weil es nicht in das zweite Byte passt:
- Ein zweites Byte von
0111 1110
oder 126
bedeutet, dass die folgenden zwei Bytes für die Länge verwendet werden
- Ein zweites Byte von
0111 1111
oder 127
bedeutet, dass die folgenden acht Bytes für die Länge verwendet werden
Die vier Maskenbytes werden zum Decodieren der tatsächlich gesendeten Daten verwendet. Der Algorithmus zum Decodieren ist wie folgt:
decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]
Wo encodedByte
ist das ursprüngliche Byte in den Daten, encodedByteIndex
ist der Index (Offset) des Bytes, der vom ersten Byte der realen Daten mit Index zählt 0
.masks
ist ein Array, das die vier Maskenbytes enthält.
Dies führt zu folgendem Pseudocode zum Decodieren:
secondByte = bytes[1]
length = secondByte AND 127 // may not be the actual length in the two special cases
indexFirstMask = 2 // if not a special case
if length == 126 // if a special case, change indexFirstMask
indexFirstMask = 4
else if length == 127 // ditto
indexFirstMask = 10
masks = bytes.slice(indexFirstMask, 4) // four bytes starting from indexFirstMask
indexFirstDataByte = indexFirstMask + 4 // four bytes further
decoded = new array
decoded.length = bytes.length - indexFirstDataByte // length of real data
for i = indexFirstDataByte, j = 0; i < bytes.length; i++, j++
decoded[j] = bytes[i] XOR masks[j MOD 4]
// now use "decoded" to interpret the received data
1000 0001
(129) für einen Textrahmen? Die Spezifikation sagt :%x1 denotes a text frame
. Also sollte es0000 0001
(0x01
) sein, oder?0001
, wie im Header dieses Teils der Spezifikation angegeben: "Opcode: 4 Bit". Das erste Byte besteht aus FIN, RSV1-3 und Opcode. FIN ist1
, RSV1-3 sind alle drei0
und der Opcode0001
summiert sich1000 0001
für das erste Byte. Sehen Sie sich auch das Bildmaterial in der Spezifikation an, das zeigt, wie die Bytes in die verschiedenen Teile aufgeteilt sind.Java-Implementierung (falls erforderlich)
Lesen: Client zu Server
Schreiben: Server zu Client
quelle
JavaScript-Implementierung:
quelle
2^31 - 1
.C # -Implementierung
Browser -> Server
Server -> Browser
quelle
test�c=ܝX[
in dem "Test" meine Nachricht ist. Woher kommt der andere Teil?Die Antwort von pimvdb wurde in Python implementiert:
Ein Anwendungsbeispiel:
quelle
Zusätzlich zur PHP-Frame-Codierungsfunktion folgt hier eine Decodierungsfunktion:
Ich habe diese und auch andere Funktionen in einer benutzerfreundlichen WebSocket PHP-Klasse hier implementiert .
quelle
PHP-Implementierung:
quelle
Vielen Dank für die Antwort, ich möchte die Python-Version von hfern (oben) erweitern, um die Sendefunktion einzuschließen, wenn jemand interessiert ist.
Verwendung zum Lesen:
Verwendung zum Schreiben:
quelle
Implementierung in Go
Teil verschlüsseln (Server -> Browser)
Teil dekodieren (Browser -> Server)
quelle
Clojure, die Decodierungsfunktion setzt voraus, dass der Frame als Map von gesendet wird
{:data byte-array-buffer :size int-size-of-buffer}
, dass der , da die tatsächliche Größe je nach Blockgröße Ihres Eingabestreams möglicherweise nicht mit der Größe des Byte-Arrays übereinstimmt.Code hier veröffentlicht: https://gist.github.com/viperscape/8918565
quelle
C ++ Implementierung (nicht von mir) hier . Beachten Sie, dass Sie, wenn Ihre Bytes über 65535 liegen, mit einem langen Wert verschieben müssen, wie hier gezeigt .
quelle