【问题标题】:Java Websocket Text Frame Error at length >=128?Java Websocket文本帧错误长度> = 128?
【发布时间】:2013-08-24 11:06:46
【问题描述】:

我正在尝试重新发明轮子并创建自己的 websocket 服务器。它在 Google Chrome 和 Firefox 上都可以正常连接,并且可以正确接收和回显最长 127 个字符的文本帧。然而,除此之外,谷歌给了我以下错误:

到“ws://localhost:9999/”的 WebSocket 连接失败:必须使用最小字节数来编码长度

Firefox 有时会接收/解释前几个字符然后失败代码:1006。

服务器显示正在完整接收消息并尝试完整广播它,没有运行时错误或 .如我的 System.out.println() 所示,它也适用于 16 位长度的创建器。我来自服务器的 java 控制台读取:

websocket 服务器已启动 客户端已连接 收到消息 1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij12345678 广播:1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij12345678 第二个数据

我目前正在编写一个帧测试器来测试我通过广播发送的帧,但希望社区能够为我节省一些繁琐的工作。真正奇怪的是 126 和 127 有效载荷长度工作并反映使用 2 个字节作为长度。

public void broadcast(String mess) throws IOException {
        System.out.println("broadcasting: "+mess);
        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) {
            System.out.println("2nd data");
            frame[1] = (byte) 126;
            byte len = (byte) rawData.length;
            frame[2] = (byte) ((len >> 8) & (byte) 255);
            frame[3] = (byte) (len & (byte) 255);                
            frameCount = 4;
        } else {
            System.out.println("3rd data");
            frame[1] = (byte) 127;
            byte len = (byte) 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++;
        }
        for (OutputStream writer : writers) {
            writer.write(reply);   
            writer.flush();
        }            

    }

感谢社区的任何帮助。

【问题讨论】:

    标签: java websocket


    【解决方案1】:

    一些笔记。

    1. 您处理长度不当
    2. 您没有正确地将字符串转换为字节(必须通过 UTF-8 完成)

    这是一个简单的例子。

    下面的代码授权于:Eclipse Public License 1.0

    package websocket;
    
    import java.nio.ByteBuffer;
    import java.nio.charset.Charset;
    
    public class RawGenerate
    {
        /**
         * The overhead (maximum) for a framing header. Assuming a maximum sized payload with masking key.
         */
        public static final int OVERHEAD = 28;
    
        public ByteBuffer asClientInitiatedTextFrame(String msg)
        {
            ByteBuffer buf = ByteBuffer.allocate(msg.length() + OVERHEAD);
            putOpFin(buf,(byte)0x01,true);
            byte mask[] = new byte[] { 1, 2, 3, 4 }; // Needs to be random
            byte payload[] = msg.getBytes(Charset.forName("UTF-8")); // must be UTF-8 (per spec)
            putLengthAndMask(buf,payload.length,mask);
            for (int i = 0; i < payload.length; i++)
            {
                buf.put((byte)(payload[i] ^= mask[i % 4]));
            }
            buf.flip();
            return buf;
        }
    
        public static void putOpFin(ByteBuffer buf, byte opcode, boolean fin)
        {
            byte b = 0x00;
            if (fin)
            {
                b |= 0x80;
            }
            b |= opcode & 0x0F;
            buf.put(b);
        }
    
        public static void putLengthAndMask(ByteBuffer buf, int length, byte mask[])
        {
            if (mask != null)
            {
                assert (mask.length == 4);
                putLength(buf,length,(mask != null));
                buf.put(mask);
            }
            else
            {
                putLength(buf,length,false);
            }
        }
    
        public static void putLength(ByteBuffer buf, int length, boolean masked)
        {
            if (length < 0)
            {
                throw new IllegalArgumentException("Length cannot be negative");
            }
            byte b = (masked?(byte)0x80:0x00);
    
            if (length > 0xFF_FF)
            {
                buf.put((byte)(b | 0x7F));
                buf.put((byte)0x00);
                buf.put((byte)0x00);
                buf.put((byte)0x00);
                buf.put((byte)0x00);
                buf.put((byte)((length >> 24) & 0xFF));
                buf.put((byte)((length >> 16) & 0xFF));
                buf.put((byte)((length >> 8) & 0xFF));
                buf.put((byte)(length & 0xFF));
            }
            else if (length >= 0x7E)
            {
                buf.put((byte)(b | 0x7E));
                buf.put((byte)(length >> 8));
                buf.put((byte)(length & 0xFF));
            }
            else
            {
                buf.put((byte)(b | length));
            }
        }
    }
    

    【讨论】:

    • 感谢您的回复我目前不在,因此无法验证并且对 java 速记命令或位运算符不够熟悉,但假设您的声誉使我确信这门课程将代替我的课程。除了处理字符串,我的代码如何正确调整长度?
    • 这里没有太多简写。只需要学习二进制/十六进制以及位操作(就像大多数二进制协议一样)&amp; (AND)、| (OR)、^ (XOR)、&gt;&gt; (SHIFT RIGHT)。如果您查看您的长度代码和我的代码,您会发现对于 8 字节长度版本,您尝试使用单个 byte len 填充所有 8 个字节。哪个行不通。我只担心 4 字节(32 位)的长度,因为这已经是 java int 的限制。 (不支持长度超过 2,147,483,647 字节的缓冲区大小)
    • 所以我用你的代码代替了我的代码,它确实可以工作,但是会立即出错。 Google 错误:与“ws://localhost:9999/”的 WebSocket 连接失败:服务器不得屏蔽它发送给客户端的任何帧。由于我无法完全阅读课程,我很抱歉,你能不能引导我解决这个问题?如果我找到我将编辑或新评论的解决方案,我将继续尝试解决,再次感谢!我更改了 asClientInitiatedTextFrame 行 putLengthAndMask(buf,payload.length,mask);到 putLength(buf,payload.length,false);胡言乱语并再次关闭
    • 让它工作谢谢。我只是改变了 putLengthAndMask(buf,payload.length,mask);到 putLengthAndMask(buf,payload.length,null);并设置 buf 大小,以便我可以调用 buf.array()。不确定如何写入位 ByteBuffer buf; if(msg.length()>65535){ buf=ByteBuffer.allocate(msg.length()+10); }else if(msg.length()>125){ buf=ByteBuffer.allocate(msg.length()+4); }else{ buf=ByteBuffer.allocate(msg.length()+2); }
    • @JoakimErdfelt 这是帧编码器,对吗?这是你做过的一些图书馆吗?它在 GitHub 上的某个地方吗?我正在使用issues.apache.org/jira/browse/DIRMINA-907,恐怕那里的编码器使用了不正确的帧编码。
    猜你喜欢
    • 2020-06-12
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 2016-10-12
    • 1970-01-01
    • 2023-04-11
    相关资源
    最近更新 更多