如何在服务器端发送和接收WebSocket消息?

92
  • 如何按照协议在服务器端使用WebSocket发送和接收消息?

  • 当我从浏览器向服务器发送数据时,为什么服务器会收到看似随机的字节?数据是否已进行编码?

  • 在服务器→客户端和客户端→服务器方向上,帧是如何工作的?

13个回答

0

C++ 实现(非本人)在这里。请注意,当您的字节数超过 65535 时,您需要使用长整型进行移位,如 此处 所示。


0

更新了Haribabu Pasupathy的代码以处理TCP分段。在我的情况下,由浏览器发送的大于1024字节的websocket数据包被分割成TCP段,因此需要重新组装。

private static void processResponse(InputStream inputStream, OutputStream outputStream) throws IOException {
    int readPacketLength = 0;
    byte[] packet = new byte[1024];
    ByteArrayOutputStream packetStream = new ByteArrayOutputStream();

    while(true) {
        readPacketLength = inputStream.read(packet);

        if(readPacketLength != -1) {
            if ((packet[0] & (byte) 15) == (byte) 8) { // Disconnect packet
                outputStream.write(packet, 0, readPacketLength);
                // returning the same packet for client to terminate connection
                outputStream.flush();
                return;
            }
            byte messageLengthByte = 0;
            int messageLength = 0;
            int maskIndex = 2;
            int messageStart = 0;
            //b[0] is always text in my case so no need to check;
            byte data = packet[1];
            byte op = (byte) 127; // 0111 111
            messageLengthByte = (byte) (data & op);

            int totalPacketLength = 0;
            if (messageLengthByte == (byte) 126 || messageLengthByte == (byte) 127) {
                if (messageLengthByte == (byte) 126) {
                    maskIndex = 4;
                    // if (messageLengthInt==(byte)126), then 16-bit length is stored in packet[2] and [3]
                    ByteBuffer messageLength16Bit = ByteBuffer.allocateDirect(4);
                    messageLength16Bit.order(ByteOrder.BIG_ENDIAN);
                    messageLength16Bit.put((byte) 0x00);
                    messageLength16Bit.put((byte) 0x00);
                    messageLength16Bit.put(packet, 2, 2);
                    messageLength16Bit.flip();
                    messageLength = messageLength16Bit.getInt();
                    totalPacketLength = messageLength + 8;
                } else {
                    maskIndex = 10;
                    // if (messageLengthInt==(byte)127), then 64-bit length is stored in bytes [2] to [9]. Using only 32-bit
                    ByteBuffer messageLength64Bit = ByteBuffer.allocateDirect(4);
                    messageLength64Bit.order(ByteOrder.BIG_ENDIAN);
                    messageLength64Bit.put(packet, 6, 4);
                    messageLength64Bit.flip();
                    messageLength = messageLength64Bit.getInt();
                    totalPacketLength = messageLength + 14;
                }

                if (readPacketLength != totalPacketLength) {
                    packetStream.write(packet, 0, readPacketLength);

                    int lastPacketLength = 0;
                    while (readPacketLength < totalPacketLength) {
                        packet = new byte[1024];
                        readPacketLength += lastPacketLength = inputStream.read(packet);
                        packetStream.write(packet, 0, lastPacketLength);
                    }
                    packet = packetStream.toByteArray();
                    packetStream.reset();
                }
            }
            else { // using message length from packet[1]
                messageLength = messageLengthByte;
            }

            byte[] masks = new byte[4];
            int i=0; int j=0;
            for(i = maskIndex; i < (maskIndex+4); i++) {
                masks[j] = packet[i];
                j++;
            }

            messageStart = maskIndex + 4;

            byte[] message = new byte[messageLength];
            for(i = messageStart, j = 0; i < readPacketLength; i++, j++){
                message[j] = (byte) (packet[i] ^ masks[j % 4]);
            }
            System.out.println("Received message: " + new String(message));
            packet = new byte[1024];
        }
    }
}

0

我解决了Nitij的C#实现中“> 65535”消息长度问题。

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
    {
        var lengthAsULong = Convert.ToUInt64(length);
        frame[1] = 127;
        frame[2] = (byte)((lengthAsULong >> 56) & 255);
        frame[3] = (byte)((lengthAsULong >> 48) & 255);
        frame[4] = (byte)((lengthAsULong >> 40) & 255);
        frame[5] = (byte)((lengthAsULong >> 32) & 255);
        frame[6] = (byte)((lengthAsULong >> 24) & 255);
        frame[7] = (byte)((lengthAsULong >> 16) & 255);
        frame[8] = (byte)((lengthAsULong >> 8) & 255);
        frame[9] = (byte)(lengthAsULong & 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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接