Sunucu tarafında WebSocket mesajlarını nasıl gönderip alabilirim?


86
  • Protokole göre WebSocket kullanarak sunucu tarafında nasıl mesaj gönderip alabilirim?

  • Tarayıcıdan sunucuya veri gönderirken neden sunucuda görünüşte rastgele baytlar alıyorum? Veriler bir şekilde kodlanmış mı?

  • Çerçeveleme hem sunucu → istemci hem de istemci → sunucu yönlerinde nasıl çalışır?

Yanıtlar:


154

Not: Bu, kesin çerçeveleme biçimine göre gelen ve giden WebSocket mesajlarını işleyebilen çok önemsiz bir sunucunun nasıl uygulanacağına dair bazı açıklama ve sözde koddur. El sıkışma sürecini içermez. Ayrıca bu cevap eğitim amaçlı yapılmıştır; tam özellikli bir uygulama değildir.

Özellikler (RFC 6455)


Mesaj gönderme

(Başka bir deyişle, sunucu → tarayıcı)

Gönderdiğiniz çerçevelerin WebSocket çerçeveleme formatına göre formatlanması gerekir. Mesaj göndermek için bu format aşağıdaki gibidir:

  • veri türünü içeren bir bayt (ve önemsiz bir sunucu için kapsam dışı olan bazı ek bilgiler)
  • uzunluğu içeren bir bayt
  • uzunluk ikinci bayta uymuyorsa iki veya sekiz bayt (ikinci bayt, uzunluk için kaç bayt kullanıldığını belirten bir koddur)
  • gerçek (ham) veriler

İlk bayt bir metin çerçevesi için 1000 0001(veya 129) olacaktır .

İkinci baytın ilk biti olarak ayarlanmıştır 0çünkü verileri kodlamıyoruz (sunucudan istemciye kodlama zorunlu değildir).

Uzunluk baytlarını doğru gönderebilmek için ham verilerin uzunluğunu belirlemek gerekir:

  • eğer 0 <= length <= 125, ek bayt gerekmez
  • 126 <= length <= 65535iki ek bayta ihtiyacınız varsa ve ikinci bayta126
  • length >= 65536sekiz ek bayta ihtiyacınız varsa ve ikinci bayta127

Uzunluğun ayrı baytlara bölünmesi gerekir, bu da sağa (sekiz bitlik bir miktarla) bit kaydırmanız ve sonra yalnızca son sekiz biti yaparak AND 1111 1111(yani 255) tutmanız gerektiği anlamına gelir .

Uzunluk bayt (lar) ından sonra ham veriler gelir.

Bu, aşağıdaki sözde koda yol açar:

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)

Mesajları almak

(Başka bir deyişle, tarayıcı → sunucu)

Elde ettiğiniz çerçeveler aşağıdaki formattadır:

  • veri türünü içeren bir bayt
  • uzunluğu içeren bir bayt
  • uzunluk ikinci bayta sığmadıysa iki veya sekiz ek bayt
  • maskeler olan dört bayt (= kod çözme anahtarları)
  • gerçek veriler

İlk bayt genellikle önemli değildir - yalnızca metin gönderiyorsanız, yalnızca metin türünü kullanıyorsunuzdur. Bu durumda 1000 0001(veya 129) olacaktır .

İkinci bayt ve ek iki veya sekiz bayt biraz ayrıştırılmalıdır, çünkü uzunluk için kaç bayt kullanıldığını bilmeniz gerekir (gerçek verilerin nerede başladığını bilmeniz gerekir). Verilere zaten sahip olduğunuz için uzunluğun kendisi genellikle gerekli değildir.

İkinci baytın ilk biti her zaman 1veri maskelenir (= kodlanır) anlamına gelir. İstemciden sunucuya gönderilen mesajlar her zaman maskelenir. Yaparak ilk parçayı kaldırmanız gerekir secondByte AND 0111 1111. Ortaya çıkan baytın, ikinci bayta sığmadığı için uzunluğu temsil etmediği iki durum vardır:

  • ikinci bir bayt 0111 1110veya 126, aşağıdaki iki baytın uzunluk için kullanıldığı anlamına gelir
  • ikinci bir bayt 0111 1111veya 127, uzunluk için aşağıdaki sekiz baytın kullanıldığı anlamına gelir

Dört maske baytı, gönderilen gerçek verilerin kodunu çözmek için kullanılır. Kod çözme algoritması aşağıdaki gibidir:

decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]

burada encodedByteveriler orijinal bayt olup, encodedByteIndexbirinci bayttan bayt sayım göstergesi (ofset) olan gerçek veri indeksine sahiptir, 0. masksdört maske baytını içeren bir dizidir.

Bu, kod çözme için aşağıdaki sözde koda yol açar:

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 0001Metin çerçevesi için neden (129)? Spec diyor diyor: %x1 denotes a text frame. Yani 0000 0001( 0x01) veya?
Dennis

3
@Dennis: Çerçeve işlem kodu, 0001özelliklerin bu bölümünün başlığında belirtildiği gibi: "İşlem kodu: 4 bit". İlk bayt FIN, RSV1-3 ve işlem kodundan oluşur. FIN 1, RSV1-3'ün üçüdür 0ve işlem kodu, ilk bayta 0001kadar olan toplamıdır 1000 0001. Ayrıca, baytların farklı parçalara nasıl bölündüğünü gösteren spesifikasyondaki resme bakın.
pimvdb

Sunucu-> İstemci modelinde 'bytesFormatted [2] = (bytesRaw.length >> 56) AND 255' gibi okunan birkaç satırınız var - Bunu benim için bozabilir misiniz? VE bana mantıksal bir operatör gibi görünüyor, bu yüzden C # 'da sadece bir sayı koymanın benim için bir şey yapacağını bekleyemiyorum. Benzer şekilde, işaretlemenizdeki ">>" nin neyi göstermesi gerektiğinden emin değilim - ancak C # 'a aktarılıyor ... Benim için anlamı ne olursa olsun ...: P
DigitalJedi805

Bunu benim için çözebilecek biri varsa, C # uygulamamı bir cevap olarak göndermekten memnuniyet duyarım.
DigitalJedi805

1
@Neevek: Demek istedikleri, maske baytlarının kendilerinin tahmin edilemez olması gerektiğidir. Sabit iseler, pek bir anlamı yoktur. Temel olarak, kötü niyetli bir kullanıcı bir veri dilimine sahip olduğunda, onu maskeler olmadan çözememelidir. Maskelerin konumu öngörülebilir değilse, gerçek sunucunun kodunu çözmesi biraz zordur :)
pimvdb

26

Java uygulaması (herhangi biri gerekliyse)

Okuma: İstemciden Sunucuya

        int len = 0;            
        byte[] b = new byte[buffLenth];
        //rawIn is a Socket.getInputStream();
        while(true){
            len = rawIn.read(b);
            if(len!=-1){

                byte rLength = 0;
                int rMaskIndex = 2;
                int rDataStart = 0;
                //b[0] is always text in my case so no need to check;
                byte data = b[1];
                byte op = (byte) 127;
                rLength = (byte) (data & op);

                if(rLength==(byte)126) rMaskIndex=4;
                if(rLength==(byte)127) rMaskIndex=10;

                byte[] masks = new byte[4];

                int j=0;
                int i=0;
                for(i=rMaskIndex;i<(rMaskIndex+4);i++){
                    masks[j] = b[i];
                    j++;
                }

                rDataStart = rMaskIndex + 4;

                int messLen = len - rDataStart;

                byte[] message = new byte[messLen];

                for(i=rDataStart, j=0; i<len; i++, j++){
                    message[j] = (byte) (b[i] ^ masks[j % 4]);
                }

                parseMessage(new String(message)); 
                //parseMessage(new String(b));

                b = new byte[buffLenth];

            }
        }

Yazma: Sunucudan İstemciye

public void brodcast(String mess) throws IOException{
    byte[] rawData = mess.getBytes();

    int frameCount  = 0;
    byte[] frame = new byte[10];

    frame[0] = (byte) 129;

    if(rawData.length <= 125){
        frame[1] = (byte) rawData.length;
        frameCount = 2;
    }else if(rawData.length >= 126 && rawData.length <= 65535){
        frame[1] = (byte) 126;
        int len = rawData.length;
        frame[2] = (byte)((len >> 8 ) & (byte)255);
        frame[3] = (byte)(len & (byte)255); 
        frameCount = 4;
    }else{
        frame[1] = (byte) 127;
        int len = rawData.length;
        frame[2] = (byte)((len >> 56 ) & (byte)255);
        frame[3] = (byte)((len >> 48 ) & (byte)255);
        frame[4] = (byte)((len >> 40 ) & (byte)255);
        frame[5] = (byte)((len >> 32 ) & (byte)255);
        frame[6] = (byte)((len >> 24 ) & (byte)255);
        frame[7] = (byte)((len >> 16 ) & (byte)255);
        frame[8] = (byte)((len >> 8 ) & (byte)255);
        frame[9] = (byte)(len & (byte)255);
        frameCount = 10;
    }

    int bLength = frameCount + rawData.length;

    byte[] reply = new byte[bLength];

    int bLim = 0;
    for(int i=0; i<frameCount;i++){
        reply[bLim] = frame[i];
        bLim++;
    }
    for(int i=0; i<rawData.length;i++){
        reply[bLim] = rawData[i];
        bLim++;
    }

    out.write(reply);
    out.flush();

}

3
Okuma işlemi için uygun bir tampon uzunluğu ne olabilir?
jackgerrits

Maalesef işe yaramıyor. Boş yayını (Sunucudan İstemciye) programıma kopyaladım. Soket başarıyla bağlandı, tarayıcıya mesaj başarıyla gönderildi, ancak tarayıcı tarafından hiçbir şey alınmadı.
nick

18

JavaScript uygulaması:

function encodeWebSocket(bytesRaw){
    var bytesFormatted = new Array();
    bytesFormatted[0] = 129;
    if (bytesRaw.length <= 125) {
        bytesFormatted[1] = bytesRaw.length;
    } else if (bytesRaw.length >= 126 && bytesRaw.length <= 65535) {
        bytesFormatted[1] = 126;
        bytesFormatted[2] = ( bytesRaw.length >> 8 ) & 255;
        bytesFormatted[3] = ( bytesRaw.length      ) & 255;
    } else {
        bytesFormatted[1] = 127;
        bytesFormatted[2] = ( bytesRaw.length >> 56 ) & 255;
        bytesFormatted[3] = ( bytesRaw.length >> 48 ) & 255;
        bytesFormatted[4] = ( bytesRaw.length >> 40 ) & 255;
        bytesFormatted[5] = ( bytesRaw.length >> 32 ) & 255;
        bytesFormatted[6] = ( bytesRaw.length >> 24 ) & 255;
        bytesFormatted[7] = ( bytesRaw.length >> 16 ) & 255;
        bytesFormatted[8] = ( bytesRaw.length >>  8 ) & 255;
        bytesFormatted[9] = ( bytesRaw.length       ) & 255;
    }
    for (var i = 0; i < bytesRaw.length; i++){
        bytesFormatted.push(bytesRaw.charCodeAt(i));
    }
    return bytesFormatted;
}

function decodeWebSocket (data){
    var datalength = data[1] & 127;
    var indexFirstMask = 2;
    if (datalength == 126) {
        indexFirstMask = 4;
    } else if (datalength == 127) {
        indexFirstMask = 10;
    }
    var masks = data.slice(indexFirstMask,indexFirstMask + 4);
    var i = indexFirstMask + 4;
    var index = 0;
    var output = "";
    while (i < data.length) {
        output += String.fromCharCode(data[i++] ^ masks[index++ % 4]);
    }
    return output;
}

5
Muhtemelen JavaScript'in 2^31 - 1,.
pimvdb

13

C # Uygulama

Tarayıcı -> Sunucu

    private String DecodeMessage(Byte[] bytes)
    {
        String incomingData = String.Empty;
        Byte secondByte = bytes[1];
        Int32 dataLength = secondByte & 127;
        Int32 indexFirstMask = 2;
        if (dataLength == 126)
            indexFirstMask = 4;
        else if (dataLength == 127)
            indexFirstMask = 10;

        IEnumerable<Byte> keys = bytes.Skip(indexFirstMask).Take(4);
        Int32 indexFirstDataByte = indexFirstMask + 4;

        Byte[] decoded = new Byte[bytes.Length - indexFirstDataByte];
        for (Int32 i = indexFirstDataByte, j = 0; i < bytes.Length; i++, j++)
        {
            decoded[j] = (Byte)(bytes[i] ^ keys.ElementAt(j % 4));
        }

        return incomingData = Encoding.UTF8.GetString(decoded, 0, decoded.Length);
    }

Sunucu -> Tarayıcı

    private static Byte[] EncodeMessageToSend(String message)
    {
        Byte[] response;
        Byte[] bytesRaw = Encoding.UTF8.GetBytes(message);
        Byte[] frame = new Byte[10];

        Int32 indexStartRawData = -1;
        Int32 length = bytesRaw.Length;

        frame[0] = (Byte)129;
        if (length <= 125)
        {
            frame[1] = (Byte)length;
            indexStartRawData = 2;
        }
        else if (length >= 126 && length <= 65535)
        {
            frame[1] = (Byte)126;
            frame[2] = (Byte)((length >> 8) & 255);
            frame[3] = (Byte)(length & 255);
            indexStartRawData = 4;
        }
        else
        {
            frame[1] = (Byte)127;
            frame[2] = (Byte)((length >> 56) & 255);
            frame[3] = (Byte)((length >> 48) & 255);
            frame[4] = (Byte)((length >> 40) & 255);
            frame[5] = (Byte)((length >> 32) & 255);
            frame[6] = (Byte)((length >> 24) & 255);
            frame[7] = (Byte)((length >> 16) & 255);
            frame[8] = (Byte)((length >> 8) & 255);
            frame[9] = (Byte)(length & 255);

            indexStartRawData = 10;
        }

        response = new Byte[indexStartRawData + length];

        Int32 i, reponseIdx = 0;

        //Add the frame bytes to the reponse
        for (i = 0; i < indexStartRawData; i++)
        {
            response[reponseIdx] = frame[i];
            reponseIdx++;
        }

        //Add the data bytes to the response
        for (i = 0; i < length; i++)
        {
            response[reponseIdx] = bytesRaw[i];
            reponseIdx++;
        }

        return response;
    }

1
Kod çözme işlevi her zaman benim için tanımlanmamış bir ek ile özel mesajımı döndürür, burada test�c=ܝX[olduğu gibi burada "test" benim mesajımdır. Diğer kısım nereden geliyor?
Snickbrack

1
Geç cevap verdiğim için özür dilerim. Web soketlerini denemek için küçük bir C # uygulaması (Konsol ve Web) oluşturdum. Nasıl kodlandığını görmek için buradan indirebilirsiniz. Bağlantı: dropbox.com/s/gw8hjsov1u6f7c0/Web%20Sockets.rar?dl=0
Nitij

Bu benim için büyük mesajlarda başarısız oldu. Uzunluk> 65535 kodunu şununla değiştirdim: var l = Convert.ToUInt64 (uzunluk); var b = BitConverter.GetBytes (l); Array.Reverse (b, 0, b.Length); b.CopyTo (çerçeve, 2); ... bazı şeyleri düzeltmiş gibi görünüyor.
Sean

Aferin. Tek bir şey var: DecodeMessage'da, "bayt" dizi uzunluğu tam olamadığı için veri çerçevesine dahil edilen Yük uzunluğu verilerine dayanarak "kodu çözülmüş" dizi uzunluğunu hesaplıyorum. "bayt" dizisi uzunluğu, akışın okunma şekline bağlıdır.
user1011138

@Sean, büyük mesaj problemini çözmek için bana tam bir örnek gösterebilir misin? bu kodu sizin örneğinizle değiştiremiyorum.
Ali Yousefi

6

pimvdb'nin cevabı python'da uygulandı:

def DecodedCharArrayFromByteStreamIn(stringStreamIn):
    #turn string values into opererable numeric byte values
    byteArray = [ord(character) for character in stringStreamIn]
    datalength = byteArray[1] & 127
    indexFirstMask = 2 
    if datalength == 126:
        indexFirstMask = 4
    elif datalength == 127:
        indexFirstMask = 10
    masks = [m for m in byteArray[indexFirstMask : indexFirstMask+4]]
    indexFirstDataByte = indexFirstMask + 4
    decodedChars = []
    i = indexFirstDataByte
    j = 0
    while i < len(byteArray):
        decodedChars.append( chr(byteArray[i] ^ masks[j % 4]) )
        i += 1
        j += 1
    return decodedChars

Bir kullanım örneği:

fromclient = '\x81\x8c\xff\xb8\xbd\xbd\xb7\xdd\xd1\xd1\x90\x98\xea\xd2\x8d\xd4\xd9\x9c'
# this looks like "?ŒOÇ¿¢gÓ ç\Ð=«ož" in unicode, received by server
print DecodedCharArrayFromByteStreamIn(fromclient)
# ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!']

Kodunuzu senaryomda kullanmaya çalıştım, ancak başarılı olamadım. Belki yardım edebilir misin? stackoverflow.com/questions/43748377/…
yak

5

PHP çerçeve kodlama işlevine ek olarak, burada bir kod çözme işlevi izler:

function Decode($M){
    $M = array_map("ord", str_split($M));
    $L = $M[1] AND 127;

    if ($L == 126)
        $iFM = 4;
    else if ($L == 127)
        $iFM = 10;
    else
        $iFM = 2;

    $Masks = array_slice($M, $iFM, 4);

    $Out = "";
    for ($i = $iFM + 4, $j = 0; $i < count($M); $i++, $j++ ) {
        $Out .= chr($M[$i] ^ $Masks[$j % 4]);
    }
    return $Out;
}

Ben kolay kullanımlı WebSocket PHP sınıfında bu ve aynı zamanda diğer fonksiyonları uyguladık burada .


4

PHP Uygulaması:

function encode($message)
{
    $length = strlen($message);

    $bytesHeader = [];
    $bytesHeader[0] = 129; // 0x1 text frame (FIN + opcode)

    if ($length <= 125) {
            $bytesHeader[1] = $length;
    } else if ($length >= 126 && $length <= 65535) {
            $bytesHeader[1] = 126;
            $bytesHeader[2] = ( $length >> 8 ) & 255;
            $bytesHeader[3] = ( $length      ) & 255;
    } else {
            $bytesHeader[1] = 127;
            $bytesHeader[2] = ( $length >> 56 ) & 255;
            $bytesHeader[3] = ( $length >> 48 ) & 255;
            $bytesHeader[4] = ( $length >> 40 ) & 255;
            $bytesHeader[5] = ( $length >> 32 ) & 255;
            $bytesHeader[6] = ( $length >> 24 ) & 255;
            $bytesHeader[7] = ( $length >> 16 ) & 255;
            $bytesHeader[8] = ( $length >>  8 ) & 255;
            $bytesHeader[9] = ( $length       ) & 255;
    }

    $str = implode(array_map("chr", $bytesHeader)) . $message;

    return $str;
}

4

Cevabınız için teşekkürler , ilgilenen herhangi biri varsa Gönderme işlevini eklemek için hfern'in (yukarıda) Python sürümüne eklemek istiyorum .

def DecodedWebsockRecieve(stringStreamIn):
    byteArray =  stringStreamIn 
    datalength = byteArray[1] & 127
    indexFirstMask = 2 
    if datalength == 126:
        indexFirstMask = 4
    elif datalength == 127:
        indexFirstMask = 10
    masks = [m for m in byteArray[indexFirstMask : indexFirstMask+4]]
    indexFirstDataByte = indexFirstMask + 4
    decodedChars = []
    i = indexFirstDataByte
    j = 0
    while i < len(byteArray):
        decodedChars.append( chr(byteArray[i] ^ masks[j % 4]) )
        i += 1
        j += 1
    return ''.join(decodedChars)

def EncodeWebSockSend(socket,data):
    bytesFormatted = []
    bytesFormatted.append(129)

    bytesRaw = data.encode()
    bytesLength = len(bytesRaw)
    if bytesLength <= 125 :
        bytesFormatted.append(bytesLength)
    elif bytesLength >= 126 and bytesLength <= 65535 :
        bytesFormatted.append(126)
        bytesFormatted.append( ( bytesLength >> 8 ) & 255 )
        bytesFormatted.append( bytesLength & 255 )
    else :
        bytesFormatted.append( 127 )
        bytesFormatted.append( ( bytesLength >> 56 ) & 255 )
        bytesFormatted.append( ( bytesLength >> 48 ) & 255 )
        bytesFormatted.append( ( bytesLength >> 40 ) & 255 )
        bytesFormatted.append( ( bytesLength >> 32 ) & 255 )
        bytesFormatted.append( ( bytesLength >> 24 ) & 255 )
        bytesFormatted.append( ( bytesLength >> 16 ) & 255 )
        bytesFormatted.append( ( bytesLength >>  8 ) & 255 )
        bytesFormatted.append( bytesLength & 255 )

    bytesFormatted = bytes(bytesFormatted)
    bytesFormatted = bytesFormatted + bytesRaw
    socket.send(bytesFormatted) 

Okumak için kullanım:

bufSize = 1024     
read = DecodedWebsockRecieve(socket.recv(bufSize))

Yazmak için kullanım:

EncodeWebSockSend(sock,"hellooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo")

2

Go'da Uygulama

Parçayı kodlayın (sunucu -> tarayıcı)

func encode (message string) (result []byte) {
  rawBytes := []byte(message)
  var idxData int

  length := byte(len(rawBytes))
  if len(rawBytes) <= 125 { //one byte to store data length
    result = make([]byte, len(rawBytes) + 2)
    result[1] = length
    idxData = 2
  } else if len(rawBytes) >= 126 && len(rawBytes) <= 65535 { //two bytes to store data length
    result = make([]byte, len(rawBytes) + 4)
    result[1] = 126 //extra storage needed
    result[2] = ( length >> 8 ) & 255
    result[3] = ( length      ) & 255
    idxData = 4
  } else {
    result = make([]byte, len(rawBytes) + 10)
    result[1] = 127
    result[2] = ( length >> 56 ) & 255
    result[3] = ( length >> 48 ) & 255
    result[4] = ( length >> 40 ) & 255
    result[5] = ( length >> 32 ) & 255
    result[6] = ( length >> 24 ) & 255
    result[7] = ( length >> 16 ) & 255
    result[8] = ( length >>  8 ) & 255
    result[9] = ( length       ) & 255
    idxData = 10
  }

  result[0] = 129 //only text is supported

  // put raw data at the correct index
  for i, b := range rawBytes {
    result[idxData + i] = b
  }
  return
}

Parçayı çöz (tarayıcı -> sunucu)

func decode (rawBytes []byte) string {
  var idxMask int
  if rawBytes[1] == 126 {
    idxMask = 4
  } else if rawBytes[1] == 127 {
    idxMask = 10
  } else {
    idxMask = 2
  }

  masks := rawBytes[idxMask:idxMask + 4]
  data := rawBytes[idxMask + 4:len(rawBytes)]
  decoded := make([]byte, len(rawBytes) - idxMask + 4)

  for i, b := range data {
    decoded[i] = b ^ masks[i % 4]
  }
  return string(decoded)
}

2

Clojure, kod çözme işlevi çerçevenin eşlemesi olarak gönderildiğini varsayar {:data byte-array-buffer :size int-size-of-buffer}, çünkü gerçek boyut, girdi akışınızın yığın boyutuna bağlı olarak bayt dizisi ile aynı boyutta olmayabilir.

Burada yayınlanan kod: https://gist.github.com/viperscape/8918565

(defn ws-decode [frame]
  "decodes websocket frame"
  (let [data (:data frame)
        dlen (bit-and (second data) 127)
        mstart (if (== dlen 127) 10 (if (== dlen 126) 4 2))
        mask (drop 2 (take (+ mstart 4) data))
        msg (make-array Byte/TYPE (- (:size frame) (+ mstart 4)))]
   (loop [i (+ mstart 4), j 0]
      (aset-byte msg j (byte (bit-xor (nth data i) (nth mask (mod j 4)))))
      (if (< i (dec(:size frame))) (recur (inc i) (inc j))))
    msg))

(defn ws-encode [data]
  "takes in bytes, return websocket frame"
  (let [len (count data)
        blen (if (> len 65535) 10 (if (> len 125) 4 2))
        buf (make-array Byte/TYPE (+ len blen))
        _ (aset-byte buf 0 -127) ;;(bit-or (unchecked-byte 0x80) 
                                           (unchecked-byte 0x1)
        _ (if (= 2 blen) 
            (aset-byte buf 1 len) ;;mask 0, len
            (do
              (dorun(map #(aset-byte buf %1 
                      (unchecked-byte (bit-and (bit-shift-right len (*(- %2 2) 8))
                                               255)))
                      (range 2 blen) (into ()(range 2 blen))))
              (aset-byte buf 1 (if (> blen 4) 127 126))))
        _ (System/arraycopy data 0 buf blen len)]
    buf))

0

C ++ Uygulaması (benim tarafımdan değil) burada . Baytlarınız 65535'in üzerinde olduğunda, burada gösterildiği gibi uzun bir değerle kaydırmanız gerektiğini unutmayın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.