Websocket Permessage-deflate не происходит в направлении сервера → клиента

Я написал свою собственную реализацию веб-сокета на Python, чтобы научиться их внутреннему устройству. Я собирался отправлять большие повторяющиеся объекты JSON через веб-узел, поэтому я пытаюсь внедрить . Сжатие работает в направление, но не в Направление Ниже представлен обмен заголовками:

Запрос

      Host: awebsite.com:port
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Upgrade: websocket
Origin: http://awebsite.com
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Sec-WebSocket-Key: JItmF32mfGXXKYyhcEoW/A==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

Ответ

      Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Accept: zYQKJ6gvwlTU/j2xw1Kf0BErg9c=

Когда я это делаю, я получаю от клиента сжатые данные, как и ожидалось, и они увеличиваются, как и ожидалось.

Когда я отправляю несжатое сообщение, я получаю нормальный ответ на клиенте, т.е. я отправляю «привет» и получаю «привет».

Когда я пытаюсь выкачать свое сообщение с помощью этой простой функции Python:

      def deflate(self,data,B64_encode=False):
   data=zlib.compress(data)
   if B64_encode:
       return base64.b64encode(data[2:-4])
   else:
       return data[2:-4]

Я получаю сообщение об ошибке о том, что символы не являются utf-8, и когда я кодирую сжатое сообщение base64, я просто получаю строку в кодировке base64. Я также попытался отправить данные в двоичном формате через веб-узел и получить на другом конце двоичный объект. Я уже некоторое время рыскал по Интернету и не слышал об этом. Думаю, я сжимаю данные не на том шаге. Ниже представлена ​​функция, которую я использую для отправки данных. До сих пор я загружал сжатое сообщение в функция, потому что из того, что я прочитал, сжатие пермессажа происходит на уровне сообщения, а все остальные данные остаются несжатыми.

      def send(self, string, TYPE="TEXT"):
                import struct
                conn = self.conn
                datatypes = {
                        "TEXT": 0x01,
                        "BINARY": 0x02,
                        "CLOSE": 0X08,
                        "PING": 0x09,
                        "PONG": 0x0A}
                b1 = 0x80
                b2 = 0
                message = ""
                if TYPE == "TEXT":
                        if type(string) == unicode:
                                b1 |= datatypes["TEXT"]
                                payload = string.encode("UTF8")
                        elif type(string) == str:
                                b1 |= datatypes["TEXT"]
                                payload = string
                                message += chr(b1)
                else:
                        b1 |= datatypes[TYPE]
                        payload = string
                        message += chr(b1)
                length = len(payload)
                if length < 126:
                        b2 |= length
                        message += chr(b2)
                elif length < (2 ** 16) - 1:
                        b2 |= 126
                        message += chr(b2)
                        l = struct.pack(">H", length)
                        message += l
                else:
                        l = struct.pack(">Q", length)
                        b2 |= 127
                        message += chr(b2)
                        message += l
                message += payload
                try:
                        conn.send(str(message))
                except socket.error:
                        traceback.print_exc()
                        conn.close()
                if TYPE == "CLOSE":
                        self.Die = True
                        conn.shutdown(2)
                        conn.close()
                        print self.myid,"Closed"

1 ответ

После долгих поисков я обнаружил, что моей проблемой был "RTFM". В третьем абзаце (а?) В Manua л на perMessage сжатии он говорит

Клиент WebSocket может предлагать несколько PMCE во время
рукопожатия открытия WebSocket. Одноранговый сервер WebSocket, получивший эти предложения, может выбрать и принять предпочтительное одно или отклонить все из них. PMCE используют
бит RSV1 заголовка кадра WebSocket, чтобы указать,
сжато сообщение или нет, так что конечная точка может решить не
сжимать сообщения с несжимаемым содержимым.

Я не знал, что делают биты rsv, когда впервые установил это, и по умолчанию для них было установлено значение 0. Мой код теперь позволяет устанавливать сжатие в send()функция в моей программе. Он красиво сжимает мои сообщения с 30200 до 149 байтов.

Мой измененный код теперь выглядит так:

              def deflate2(self,data):
            data=zlib.compress(data)
            data=data[2:-4]
            return data

        def send(self, string, TYPE="TEXT",deflate=False):
                import struct
                if (deflate):
                    string=self.deflate(string)
                conn = self.conn
                datatypes = {
                        "TEXT": 0x01,
                        "BINARY": 0x02,
                        "CLOSE": 0X08,
                        "PING": 0x09,
                        "PONG": 0x0A}
                b1 = 0x80              #0b100000000
                if(deflate): b1=0xC0   #0b110000000 sets RSV1 to 1 for compression
                b2 = 0
                message = ""
                if TYPE == "TEXT":
                        if type(string) == unicode:
                                b1 |= datatypes["TEXT"]
                                payload = string.encode("UTF8")
                        elif type(string) == str:
                                b1 |= datatypes["TEXT"]
                                payload = string
                                message += chr(b1)
                else:
                        b1 |= datatypes[TYPE]
                        payload = string
                        message += chr(b1)
                length = len(payload)
                if length < 126:
                        b2 |= length
                        message += chr(b2)
                elif length < (2 ** 16) - 1:
                        b2 |= 126
                        message += chr(b2)
                        l = struct.pack(">H", length)
                        message += l
                else:
                        l = struct.pack(">Q", length)
                        b2 |= 127
                        message += chr(b2)
                        message += l
                message += payload
                try:
                        if self.debug:
                            for x in message: print("S>: ",x,hex(ord(x)),ord(x))
                        conn.send(str(message))
                except socket.error:
                        traceback.print_exc()
                        conn.close()
                if TYPE == "CLOSE":
                        self.Die = True
                        conn.shutdown(2)
                        conn.close()
                        print self.myid,"Closed"
Другие вопросы по тегам