Chunking WebSocket Transmission

Ponieważ używam połączeń WebSocket na bardziej regularnych bazach, byłem zainteresowany tym, jak wszystko działa pod maską. Przez jakiś czas zagłębiałem się w niekończące się dokumenty specyfikacji, ale jak dotąd nie mogłem znaleźć nic na temat chunking samego strumienia transmisji.

Protokół WebSocket wywołuje ramki danych (które opisują czysty strumień danych, więc jego również nazywa się ramki bez kontroli). O ile rozumiem spec, nie ma zdefiniowanej maksymalnej długości i brak zdefiniowanej wartości MTU (maximum transfer unit), co z kolei oznacza, że pojedyncza ramka danych WebSocket może zawierać, przez spec(!), nieskończoną ilość danych (Proszę mnie poprawić, jeśli się mylę, nadal jestem studentem w tym zakresie).

Po przeczytaniu tego, od razu skonfigurowałem mój mały Node WebSocket server. Ponieważ mam silną historię Ajax (również na streamingu i Comet), moje oczekiwania początkowo były takie, " musi być jakiś interaktywny tryb odczytu danych, podczas gdy jest przenoszona ". Ale mylę się, prawda ?

Zacząłem od małego, z 4KB danych.

Serwer

testSocket.emit( 'data', new Array( 4096 ).join( 'X' ) );

I tak jak oczekiwano, dociera to do klienta jako jeden fragment danych

Klient

wsInstance.onmessage = function( data ) {
    console.log( data.length ); // 4095
};

Więc zwiększyłem ładowność i spodziewałem się ponownie, że w pewnym momencie, po stronie klienta onmessage handler będzie strzelać powtarzalnie, skutecznie chunking transmisji. Ale ku mojemu szoku, to się nigdy nie wydarzyło. ( node-server , testowany na firefox, chrome i safari Po stronie klienta). Mój największy ładunek to 80 MB

testSocket.emit( 'data', new Array( 1024*1024*80 ).join( 'X' ) );

I nadal dotarł w jednym kawałku danych o kliencie. Oczywiście zajmuje to trochę czasu, nawet jeśli masz całkiem dobre połączenie. Pytania są tutaj

  • czy jest jakaś możliwość chunkowania tych strumieni, podobnie jak w trybie XHR readyState3 ?
  • czy istnieje limit rozmiaru dla pojedynczego ws data-frame ?
  • czy websockets nie powinny przenosić tak dużych ładunków? (co sprawia, że zastanawiam się ponownie, dlaczego nie ma zdefiniowanego max-size)

Nadal mogę spojrzeć z niewłaściwej perspektywy na WebSockets, prawdopodobnie potrzeba wysyłania dużych ilości danych po prostu nie ma i należy chować/dzielić logicznie żadnych danych przed wysłaniem ?

Author: jAndy, 2012-10-22

2 answers

Najpierw należy odróżnić protokół WebSocket i API WebSocket wewnątrz przeglądarki.

Protokół WebSocket ma limit rozmiaru ramki wynoszący 2^63 oktety, ale wiadomość WebSocket może składać się z nieograniczonej liczby klatek.

[[0]}API WebSocket w przeglądarkach nie wyświetla API opartego na ramkach lub streamingu, ale tylko API opartego na wiadomościach. Ładunek przychodzącej wiadomości jest zawsze całkowicie buforowany (w ramach implementacja WebSocket przeglądarki) przed udostępnieniem jej do JavaScript.

API innych implementacji WebSocket mogą zapewnić dostęp do danych przesyłanych za pośrednictwem protokołu WebSocket w oparciu o ramki lub strumieniowo. Na przykład, AutobahnPython robi. Więcej można przeczytać w przykładach tutaj https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/streaming.

Ujawnienie: jestem oryginalnym autorem Autobahn i pracy dla Tavendo.

Więcej rozważań:

Tak długo, jak nie ma ramki / streaming API w przeglądarce JS WebSocket API, można tylko odbierać / wysyłać pełne wiadomości ws.

Pojedyncze (zwykłe) połączenie WebSocket nie może przeplatać ładunku wielu wiadomości. Jeśli więc używasz dużych wiadomości, są one dostarczane w kolejności i nie będziesz w stanie wysyłać małych wiadomości pomiędzy, gdy duża wiadomość jest nadal w locie.

Istnieje nadchodzące rozszerzenie WebSocket (extensions są wbudowanym mechanizmem rozszerzającym protokół): multipleksowanie WebSocket. Pozwala to na posiadanie wielu (logicznych) połączeń WebSocket przez jedno podstawowe połączenie TCP, co ma wiele zalet.

Uwaga: możesz otworzyć wiele połączeń WS (przez różne podstawowe TCP) do jednego serwera docelowego z jednej strony JS / HTML dzisiaj .

Uwaga również: można zrobić "chunking" siebie w warstwie aplikacji: wyślij swoje rzeczy w mniejszych wiadomościach WS ponownie zmontować siebie.

Zgadzam się, w idealnym świecie, miałbyś message / frame / streaming API w przeglądarce plus multipleksowanie WebSocket. To daje całą moc i wygodę.

 78
Author: oberstet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-03 15:47:31

Sekcja RFC 6455 1.1:

Oto, co zapewnia protokół WebSocket: [...] alternatywa dla HTTP dla dwukierunkowej komunikacji ze strony internetowej do zdalnego serwera .

Jak stwierdzono, Websockety służą do komunikacji między stroną internetową a serwerem. Zwróć uwagę na różnicę między stroną internetową a przeglądarką internetową . Przykładami są gry przeglądarkowe i aplikacje do czatu, które pomijają wiele małych wiadomości.

Jeśli chcesz wysłać wiele MB w jednej wiadomości, myślę, że nie używasz Websocketów tak, jak były zamierzone. Jeśli chcesz przesłać pliki, zrób to za pomocą zwykłego starego żądania Http, odpowiedzi Content-Disposition, aby umożliwić przeglądarce pobranie pliku.

Więc jeśli wyjaśnisz, dlaczego chcesz wysyłać tak duże ilości danych, być może ktoś pomoże wymyślić bardziej eleganckie rozwiązanie niż korzystanie z WebSockets.

Poza tym klient lub serwer może odmówić zbyt dużych wiadomości (chociaż nie jest wyraźnie określone Jak odmówi):

Sekcja RFC 6455 10.4:

Implementacje, które mają implementację i / lub platformę ograniczenia dotyczące rozmiaru ramki lub całkowitej wielkości wiadomości po montaż z wielu ramek musi zabezpieczyć się przed przekroczenie tych limitów. (Na przykład złośliwy punkt końcowy może spróbować aby wyczerpać pamięć swojego peera lub przeprowadzić atak typu denial-of-service przez wysyłanie albo pojedyncza duża ramka (np. o rozmiarze 2 * * 60) lub wysyłając długi strumień małych ramek, które są częścią rozdrobnionego wiadomość.) Taka realizacja powinna nakładać ograniczenie na ramkę rozmiary i całkowity rozmiar wiadomości po ponownym złożeniu z wielu ramki.

 10
Author: CodeCaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-24 12:44:52