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

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

  • 当我从浏览器向服务器发送数据时,为什么我在服务器上得到看似随机的字节?数据被加密了吗?

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

111259 次浏览

Note: This is some explanation and pseudocode as to how to implement a very trivial server that can handle incoming and outcoming WebSocket messages as per the definitive framing format. It does not include the handshaking process. Furthermore, this answer has been made for educational purposes; it is not a full-featured implementation.

Specification (RFC 6455)


Sending messages

(In other words, server → browser)

The frames you're sending need to be formatted according to the WebSocket framing format. For sending messages, this format is as follows:

  • one byte which contains the type of data (and some additional info which is out of scope for a trivial server)
  • one byte which contains the length
  • either two or eight bytes if the length does not fit in the second byte (the second byte is then a code saying how many bytes are used for the length)
  • the actual (raw) data

The first byte will be 1000 0001 (or 129) for a text frame.

The second byte has its first bit set to 0 because we're not encoding the data (encoding from server to client is not mandatory).

It is necessary to determine the length of the raw data so as to send the length bytes correctly:

  • if 0 <= length <= 125, you don't need additional bytes
  • if 126 <= length <= 65535, you need two additional bytes and the second byte is 126
  • if length >= 65536, you need eight additional bytes, and the second byte is 127

The length has to be sliced into separate bytes, which means you'll need to bit-shift to the right (with an amount of eight bits), and then only retain the last eight bits by doing AND 1111 1111 (which is 255).

After the length byte(s) comes the raw data.

This leads to the following pseudocode:

bytesFormatted[0] = 129


indexStartRawData = -1 // it doesn't matter what value is
// set here - it will be set now:


if bytesRaw.length <= 125
bytesFormatted[1] = bytesRaw.length


indexStartRawData = 2


else if bytesRaw.length >= 126 and bytesRaw.length <= 65535
bytesFormatted[1] = 126
bytesFormatted[2] = ( bytesRaw.length >> 8 ) AND 255
bytesFormatted[3] = ( bytesRaw.length      ) AND 255


indexStartRawData = 4


else
bytesFormatted[1] = 127
bytesFormatted[2] = ( bytesRaw.length >> 56 ) AND 255
bytesFormatted[3] = ( bytesRaw.length >> 48 ) AND 255
bytesFormatted[4] = ( bytesRaw.length >> 40 ) AND 255
bytesFormatted[5] = ( bytesRaw.length >> 32 ) AND 255
bytesFormatted[6] = ( bytesRaw.length >> 24 ) AND 255
bytesFormatted[7] = ( bytesRaw.length >> 16 ) AND 255
bytesFormatted[8] = ( bytesRaw.length >>  8 ) AND 255
bytesFormatted[9] = ( bytesRaw.length       ) AND 255


indexStartRawData = 10


// put raw data at the correct index
bytesFormatted.put(bytesRaw, indexStartRawData)




// now send bytesFormatted (e.g. write it to the socket stream)

Receiving messages

(In other words, browser → server)

The frames you obtain are in the following format:

  • one byte which contains the type of data
  • one byte which contains the length
  • either two or eight additional bytes if the length did not fit in the second byte
  • four bytes which are the masks (= decoding keys)
  • the actual data

The first byte usually does not matter - if you're just sending text you are only using the text type. It will be 1000 0001 (or 129) in that case.

The second byte and the additional two or eight bytes need some parsing, because you need to know how many bytes are used for the length (you need to know where the real data starts). The length itself is usually not necessary since you have the data already.

The first bit of the second byte is always 1 which means the data is masked (= encoded). Messages from the client to the server are always masked. You need to remove that first bit by doing secondByte AND 0111 1111. There are two cases in which the resulting byte does not represent the length because it did not fit in the second byte:

  • a second byte of 0111 1110, or 126, means the following two bytes are used for the length
  • a second byte of 0111 1111, or 127, means the following eight bytes are used for the length

The four mask bytes are used for decoding the actual data that has been sent. The algorithm for decoding is as follows:

decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]

where encodedByte is the original byte in the data, encodedByteIndex is the index (offset) of the byte counting from the first byte of the real data, which has index 0. masks is an array containing of the four mask bytes.

This leads to the following pseudocode for decoding:

secondByte = bytes[1]


length = secondByte AND 127 // may not be the actual length in the two special cases


indexFirstMask = 2          // if not a special case


if length == 126            // if a special case, change indexFirstMask
indexFirstMask = 4


else if length == 127       // ditto
indexFirstMask = 10


masks = bytes.slice(indexFirstMask, 4) // four bytes starting from indexFirstMask


indexFirstDataByte = indexFirstMask + 4 // four bytes further


decoded = new array


decoded.length = bytes.length - indexFirstDataByte // length of real data


for i = indexFirstDataByte, j = 0; i < bytes.length; i++, j++
decoded[j] = bytes[i] XOR masks[j MOD 4]




// now use "decoded" to interpret the received data

pimvdb's answer implemented in python:

def DecodedCharArrayFromByteStreamIn(stringStreamIn):
#turn string values into opererable numeric byte values
byteArray = [ord(character) for character in stringStreamIn]
datalength = byteArray[1] & 127
indexFirstMask = 2
if datalength == 126:
indexFirstMask = 4
elif datalength == 127:
indexFirstMask = 10
masks = [m for m in byteArray[indexFirstMask : indexFirstMask+4]]
indexFirstDataByte = indexFirstMask + 4
decodedChars = []
i = indexFirstDataByte
j = 0
while i < len(byteArray):
decodedChars.append( chr(byteArray[i] ^ masks[j % 4]) )
i += 1
j += 1
return decodedChars

An Example of usage:

fromclient = '\x81\x8c\xff\xb8\xbd\xbd\xb7\xdd\xd1\xd1\x90\x98\xea\xd2\x8d\xd4\xd9\x9c'
# this looks like "?ŒOÇ¿¢gÓ ç\Ð=«ož" in unicode, received by server
print DecodedCharArrayFromByteStreamIn(fromclient)
# ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!']

JavaScript implementation:

function encodeWebSocket(bytesRaw){
var bytesFormatted = new Array();
bytesFormatted[0] = 129;
if (bytesRaw.length <= 125) {
bytesFormatted[1] = bytesRaw.length;
} else if (bytesRaw.length >= 126 && bytesRaw.length <= 65535) {
bytesFormatted[1] = 126;
bytesFormatted[2] = ( bytesRaw.length >> 8 ) & 255;
bytesFormatted[3] = ( bytesRaw.length      ) & 255;
} else {
bytesFormatted[1] = 127;
bytesFormatted[2] = ( bytesRaw.length >> 56 ) & 255;
bytesFormatted[3] = ( bytesRaw.length >> 48 ) & 255;
bytesFormatted[4] = ( bytesRaw.length >> 40 ) & 255;
bytesFormatted[5] = ( bytesRaw.length >> 32 ) & 255;
bytesFormatted[6] = ( bytesRaw.length >> 24 ) & 255;
bytesFormatted[7] = ( bytesRaw.length >> 16 ) & 255;
bytesFormatted[8] = ( bytesRaw.length >>  8 ) & 255;
bytesFormatted[9] = ( bytesRaw.length       ) & 255;
}
for (var i = 0; i < bytesRaw.length; i++){
bytesFormatted.push(bytesRaw.charCodeAt(i));
}
return bytesFormatted;
}


function decodeWebSocket (data){
var datalength = data[1] & 127;
var indexFirstMask = 2;
if (datalength == 126) {
indexFirstMask = 4;
} else if (datalength == 127) {
indexFirstMask = 10;
}
var masks = data.slice(indexFirstMask,indexFirstMask + 4);
var i = indexFirstMask + 4;
var index = 0;
var output = "";
while (i < data.length) {
output += String.fromCharCode(data[i++] ^ masks[index++ % 4]);
}
return output;
}

Java implementation (if any one requires)

Reading : Client to Server

        int len = 0;
byte[] b = new byte[buffLenth];
//rawIn is a Socket.getInputStream();
while(true){
len = rawIn.read(b);
if(len!=-1){


byte rLength = 0;
int rMaskIndex = 2;
int rDataStart = 0;
//b[0] is always text in my case so no need to check;
byte data = b[1];
byte op = (byte) 127;
rLength = (byte) (data & op);


if(rLength==(byte)126) rMaskIndex=4;
if(rLength==(byte)127) rMaskIndex=10;


byte[] masks = new byte[4];


int j=0;
int i=0;
for(i=rMaskIndex;i<(rMaskIndex+4);i++){
masks[j] = b[i];
j++;
}


rDataStart = rMaskIndex + 4;


int messLen = len - rDataStart;


byte[] message = new byte[messLen];


for(i=rDataStart, j=0; i<len; i++, j++){
message[j] = (byte) (b[i] ^ masks[j % 4]);
}


parseMessage(new String(message));
//parseMessage(new String(b));


b = new byte[buffLenth];


}
}

Writing : Server to Client

public void brodcast(String mess) throws IOException{
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){
frame[1] = (byte) 126;
int len = rawData.length;
frame[2] = (byte)((len >> 8 ) & (byte)255);
frame[3] = (byte)(len & (byte)255);
frameCount = 4;
}else{
frame[1] = (byte) 127;
int len = 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++;
}


out.write(reply);
out.flush();


}

Implementation in Go

Encode part (server -> browser)

func encode (message string) (result []byte) {
rawBytes := []byte(message)
var idxData int


length := byte(len(rawBytes))
if len(rawBytes) <= 125 { //one byte to store data length
result = make([]byte, len(rawBytes) + 2)
result[1] = length
idxData = 2
} else if len(rawBytes) >= 126 && len(rawBytes) <= 65535 { //two bytes to store data length
result = make([]byte, len(rawBytes) + 4)
result[1] = 126 //extra storage needed
result[2] = ( length >> 8 ) & 255
result[3] = ( length      ) & 255
idxData = 4
} else {
result = make([]byte, len(rawBytes) + 10)
result[1] = 127
result[2] = ( length >> 56 ) & 255
result[3] = ( length >> 48 ) & 255
result[4] = ( length >> 40 ) & 255
result[5] = ( length >> 32 ) & 255
result[6] = ( length >> 24 ) & 255
result[7] = ( length >> 16 ) & 255
result[8] = ( length >>  8 ) & 255
result[9] = ( length       ) & 255
idxData = 10
}


result[0] = 129 //only text is supported


// put raw data at the correct index
for i, b := range rawBytes {
result[idxData + i] = b
}
return
}

Decode part (browser -> server)

func decode (rawBytes []byte) string {
var idxMask int
if rawBytes[1] == 126 {
idxMask = 4
} else if rawBytes[1] == 127 {
idxMask = 10
} else {
idxMask = 2
}


masks := rawBytes[idxMask:idxMask + 4]
data := rawBytes[idxMask + 4:len(rawBytes)]
decoded := make([]byte, len(rawBytes) - idxMask + 4)


for i, b := range data {
decoded[i] = b ^ masks[i % 4]
}
return string(decoded)
}

Clojure, the decode function assumes frame is sent as map of {:data byte-array-buffer :size int-size-of-buffer}, because the actual size may not be the same size as the byte-array depending on chunk size of your inputstream.

Code posted here: https://gist.github.com/viperscape/8918565

(defn ws-decode [frame]
"decodes websocket frame"
(let [data (:data frame)
dlen (bit-and (second data) 127)
mstart (if (== dlen 127) 10 (if (== dlen 126) 4 2))
mask (drop 2 (take (+ mstart 4) data))
msg (make-array Byte/TYPE (- (:size frame) (+ mstart 4)))]
(loop [i (+ mstart 4), j 0]
(aset-byte msg j (byte (bit-xor (nth data i) (nth mask (mod j 4)))))
(if (< i (dec(:size frame))) (recur (inc i) (inc j))))
msg))


(defn ws-encode [data]
"takes in bytes, return websocket frame"
(let [len (count data)
blen (if (> len 65535) 10 (if (> len 125) 4 2))
buf (make-array Byte/TYPE (+ len blen))
_ (aset-byte buf 0 -127) ;;(bit-or (unchecked-byte 0x80)
(unchecked-byte 0x1)
_ (if (= 2 blen)
(aset-byte buf 1 len) ;;mask 0, len
(do
(dorun(map #(aset-byte buf %1
(unchecked-byte (bit-and (bit-shift-right len (*(- %2 2) 8))
255)))
(range 2 blen) (into ()(range 2 blen))))
(aset-byte buf 1 (if (> blen 4) 127 126))))
_ (System/arraycopy data 0 buf blen len)]
buf))

PHP Implementation:

function encode($message)
{
$length = strlen($message);


$bytesHeader = [];
$bytesHeader[0] = 129; // 0x1 text frame (FIN + opcode)


if ($length <= 125) {
$bytesHeader[1] = $length;
} else if ($length >= 126 && $length <= 65535) {
$bytesHeader[1] = 126;
$bytesHeader[2] = ( $length >> 8 ) & 255;
$bytesHeader[3] = ( $length      ) & 255;
} else {
$bytesHeader[1] = 127;
$bytesHeader[2] = ( $length >> 56 ) & 255;
$bytesHeader[3] = ( $length >> 48 ) & 255;
$bytesHeader[4] = ( $length >> 40 ) & 255;
$bytesHeader[5] = ( $length >> 32 ) & 255;
$bytesHeader[6] = ( $length >> 24 ) & 255;
$bytesHeader[7] = ( $length >> 16 ) & 255;
$bytesHeader[8] = ( $length >>  8 ) & 255;
$bytesHeader[9] = ( $length       ) & 255;
}


$str = implode(array_map("chr", $bytesHeader)) . $message;


return $str;
}

C# Implementation

Browser -> Server

    private String DecodeMessage(Byte[] bytes)
{
String incomingData = String.Empty;
Byte secondByte = bytes[1];
Int32 dataLength = secondByte & 127;
Int32 indexFirstMask = 2;
if (dataLength == 126)
indexFirstMask = 4;
else if (dataLength == 127)
indexFirstMask = 10;


IEnumerable<Byte> keys = bytes.Skip(indexFirstMask).Take(4);
Int32 indexFirstDataByte = indexFirstMask + 4;


Byte[] decoded = new Byte[bytes.Length - indexFirstDataByte];
for (Int32 i = indexFirstDataByte, j = 0; i < bytes.Length; i++, j++)
{
decoded[j] = (Byte)(bytes[i] ^ keys.ElementAt(j % 4));
}


return incomingData = Encoding.UTF8.GetString(decoded, 0, decoded.Length);
}

Server -> Browser

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

C++ Implementation (not by me) here. Note that when your bytes are over 65535, you need to shift with a long value as shown here.

In addition to the PHP frame encoding function, here follows a decode function:

function Decode($M){
$M = array_map("ord", str_split($M));
$L = $M[1] AND 127;


if ($L == 126)
$iFM = 4;
else if ($L == 127)
$iFM = 10;
else
$iFM = 2;


$Masks = array_slice($M, $iFM, 4);


$Out = "";
for ($i = $iFM + 4, $j = 0; $i < count($M); $i++, $j++ ) {
$Out .= chr($M[$i] ^ $Masks[$j % 4]);
}
return $Out;
}

I've implemented this and also other functions in an easy-to-use WebSocket PHP class here.

Thank you for the answer, i would like to add onto hfern's(above) Python version to include the Sending function if any one is interested.

def DecodedWebsockRecieve(stringStreamIn):
byteArray =  stringStreamIn
datalength = byteArray[1] & 127
indexFirstMask = 2
if datalength == 126:
indexFirstMask = 4
elif datalength == 127:
indexFirstMask = 10
masks = [m for m in byteArray[indexFirstMask : indexFirstMask+4]]
indexFirstDataByte = indexFirstMask + 4
decodedChars = []
i = indexFirstDataByte
j = 0
while i < len(byteArray):
decodedChars.append( chr(byteArray[i] ^ masks[j % 4]) )
i += 1
j += 1
return ''.join(decodedChars)


def EncodeWebSockSend(socket,data):
bytesFormatted = []
bytesFormatted.append(129)


bytesRaw = data.encode()
bytesLength = len(bytesRaw)
if bytesLength <= 125 :
bytesFormatted.append(bytesLength)
elif bytesLength >= 126 and bytesLength <= 65535 :
bytesFormatted.append(126)
bytesFormatted.append( ( bytesLength >> 8 ) & 255 )
bytesFormatted.append( bytesLength & 255 )
else :
bytesFormatted.append( 127 )
bytesFormatted.append( ( bytesLength >> 56 ) & 255 )
bytesFormatted.append( ( bytesLength >> 48 ) & 255 )
bytesFormatted.append( ( bytesLength >> 40 ) & 255 )
bytesFormatted.append( ( bytesLength >> 32 ) & 255 )
bytesFormatted.append( ( bytesLength >> 24 ) & 255 )
bytesFormatted.append( ( bytesLength >> 16 ) & 255 )
bytesFormatted.append( ( bytesLength >>  8 ) & 255 )
bytesFormatted.append( bytesLength & 255 )


bytesFormatted = bytes(bytesFormatted)
bytesFormatted = bytesFormatted + bytesRaw
socket.send(bytesFormatted)

Usage for reading:

bufSize = 1024
read = DecodedWebsockRecieve(socket.recv(bufSize))

Usage for writing:

EncodeWebSockSend(sock,"hellooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo")

Updated Haribabu Pasupathy code to deal with TCP segmentation. In my case websocket packets larger than 1024 bytes sent by browser are being splitted into TCP segments, so reassembling is required.

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];
}
}
}

I fixed the > 65535 message length issue from Nitij's C# implementation.

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;
}