java - 服务器压缩有效负载时出现 websocket 协议(protocol)错误

标签 java sockets websocket compression deflate

我正在编写一个 Java Websocket 服务器,它现在从客户端接收打开握手消息(在 Chrome 版本 57.0.2987.133(64 位)中)并响应以完成握手,两者如下所示。

Received: GET / HTTP/1.1
Received: Host: localhost:6789
Received: Connection: Upgrade
Received: Pragma: no-cache
Received: Cache-Control: no-cache
Received: Upgrade: websocket
Received: Origin: http://localhost:8080
Received: Sec-WebSocket-Version: 13
Received: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Received: Accept-Encoding: gzip, deflate, sdch, br
Received: Accept-Language: en-US,en;q=0.8
Received: Sec-WebSocket-Key: L1IiUSGijbGmTpthWsebOg==
Received: Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

Sending: HTTP/1.1 101 Switching Protocols
Sending: Upgrade: websocket
Sending: Connection: Upgrade
Sending: Sec-WebSocket-Accept: L5HXnDJGDMYbWr5gRcQMOwKNf3Q=
Sending: Accept-Encoding: gzip, deflate
Sending: Sec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover; server_no_context_takeover

现在,客户端可以发送消息,而且没有任何问题,我的代码使用 java.util.zip.Deflater 成功解压缩它们,并且...如果我的服务器以 header 字节 0x81 响应(fin、无压缩、文本) )和 0x5,然后是“hello”的字节(作为示例),然后 Chrome 上的 javascript 中的 websocket 客户端完全满意,但是当我尝试压缩响应时,客户端总是关闭连接,引用错误代码 1002 和文本“Websocket”协议(protocol)错误'。

放气

    public void sendMessageDeflated(String rxMessage, OutputStream streamOut) {

    System.out.println("Message back to client is: " + rxMessage);

    // And then compress the response and send it out.
    Deflater compressor = new Deflater(Deflater.DEFLATED);
    try {
        int headerLength = 2;
        byte unzippedMsg[] = rxMessage.getBytes("UTF-8");
        compressor.setInput(unzippedMsg);
        compressor.finish();
        byte zippedMsg[] = new byte[2048];  // Nasty constant but will have to do for now.
        int toCompressLength = unzippedMsg.length;
        int compLength = compressor.deflate(zippedMsg, headerLength, zippedMsg.length - headerLength);
        compressor.end();

        zippedMsg[0] = (byte)0xC1; // FIN bit, compression plus opcode for TEXT MESSAGE
        zippedMsg[1] = (byte)((byte)0x00 | (byte)compLength); // No mask on return data.

        streamOut.write(zippedMsg, 0, compLength + headerLength);

    } catch ( IOException ioEx ) {
        // TBD
        System.out.println("IOException: " + ioEx.toString());
    } catch ( Exception ex ) {
        // TBD
        System.out.println("IOException: " + ex.toString());
    }
}

GZIP

    public void sendMessageGZipped(String rxMessage, OutputStream streamOut) {
    // Do something with the message here...

    System.out.println("Message back to client is: " + rxMessage);

    // And then compress the response and send it out.
    try {
        int headerLength = 2;
        byte unzippedMsg[] = rxMessage.getBytes("UTF-8");
        int toCompressLength = unzippedMsg.length;

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
        gzipOut.write(unzippedMsg, 0, toCompressLength);
        gzipOut.close();
        byte[] payload = baos.toByteArray();

        byte header[] = new byte[32];
        header[0] = (byte)0xC1; // FIN bit plus opcode for TEXT MESSAGE
        header[1] = (byte)((byte)0x00 | (byte)payload.length); // No mask on return data.

        streamOut.write(header, 0, 2);
        streamOut.write(payload);

    } catch ( IOException ioEx ) {
        // TBD
        System.out.println("IOException: " + ioEx.toString());
    } catch ( Exception ex ) {
        // TBD
        System.out.println("IOException: " + ex.toString());
    }
}

我尝试切换到二进制操作码,认为压缩文本可能=二进制,但这不起作用。我真的看不出我做错了什么或错过了什么。该实现不包括跨越消息的滑动压缩窗口。我认为响应 header 已经清楚地表明了这一点。帮助感激地接受。

最佳答案

我最终通过构建客户端 websocket 代码并看到尝试膨胀消息时抛出的异常来解决这个问题:“无效的存储 block 长度”。这让我看到了这篇文章:Java decompressing array of bytes其中谈到 Deflate 能够使用或不使用 zlib 包装器进行压缩。因此,将 processMessage2 中的一行从上面的示例代码更改为...

        Deflater compressor = new Deflater(Deflater.DEFLATED, true);

...将“nowrap”设置为 true。

Chrome 浏览器客户端在其 header 中声称支持 gzip。如果我成功了,我也会回到这里并发布答案。

关于java - 服务器压缩有效负载时出现 websocket 协议(protocol)错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43254915/

相关文章:

java - 执行 postgresql 模式脚本 Spring DatabasePopulator 提示 Unterminated dollar quote started at position

java - Spring Integration 事件监听器入站适配器

java - 从元模型中消除可选字段

java - 如何为所有 Activity 建立一个共享线程?

python - websocket数据采集设计

java - 无法与远程计算机建立 RMI 连接

c# - 在 C# 应用程序之间流式传输数据

python - HTTP/1.1 与 HTTP/1.0 Python 套接字

javascript - 从 Chrome 扩展中 Hook Websocket

javascript - 将 ssl 与 websocket 一起使用时出错