Reputation: 271
I'm writing a c# web socket implementation and Whenever I send messages greater than 65535 bytes; the client (Javascript) fails to load the message and closes the connection. (It was previously saying invalid frame, now it says nothing)
I am encoding the messages like so
public 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;
}
Messages under 65535 bytes send fine. Any help is appreciated.
To clarify the message im trying to send is 120283 bytes; error code is 1006
For messages up to 125 bytes, the code is correct. For messages > 125 but <= 65536 bytes, i need to write 3 bytes - the first byte is 126; the following 2 bytes give the message length. For messages > 65536 bytes, i need to write 9 bytes - the first byte is 127; the following 8 bytes give the message length.
As you can see I do all of this in the above code, but the message fails to send .
Upvotes: 0
Views: 824
Reputation: 1
The bug is in sending a long variable, but length is Int32. There are a few ways to solve it, for example:
frame[1] = (Byte)127;
frame[2] = 0;
frame[3] = 0;
frame[4] = 0;
frame[5] = 0;
frame[6] = (Byte)((length >> 24) & 255);
frame[7] = (Byte)((length >> 16) & 255);
frame[8] = (Byte)((length >> 8) & 255);
frame[9] = (Byte)(length & 255);
I tested this code and works fine!
Upvotes: 0
Reputation: 120440
It looks like there's a bug in this:
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);
This is because you are trying to bitshift a 32bit number over 8 bytes, even though Int32
is only 4 bytes long. Net result, you end up storing the same 32bit number twice over the 8 bytes. You could convert length
to a ulong
and use that value instead, and your code should work. Otherwise...
I prefer to use someone else's code for something as boring as bitshifting.
This bitshifting code (and its bugs) has propagated far and wide (you're not the first person to see this issue).
If you grab Jon Skeet's MiscUtil from nuget, you'll get a better result with the following code (with the added bonus that it's a much easier read):
frame[1] = (byte)127;
EndianBitConverter.Big.CopyBytes((ulong)length, frame, 2);
Upvotes: 3