Reputation: 81
I am trying to reinvent the wheel and create my own websocket server. It is connecting fine on both Google Chrome and Firefox and will receive and echo text frames correctly up to 127 characters in length. However, beyond that Google gives me the following error:
WebSocket connection to 'ws://localhost:9999/' failed: The minimal number of bytes MUST be used to encode the length
Firefox will receive/interpret the first few characters sometimes then fail code:1006.
The server shows to be receiving the message in full and attempting to broadcast it in full with no run-time errors or . It's also going to the 16 bit length creator as shown by my System.out.println(). My java console from server reads:
websocket server started client connected message received 1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij12345678 broadcasting: 1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij12345678 2nd data
I'm currently writing a frame tester to test the frame I'm sending with broadcast but was hoping the community might be able to save me some of that leg work. The really odd thing is 126 and 127 payload lengths work and reflect using the 2 bytes for length.
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();
}
}
Thank you community for any help.
Upvotes: 0
Views: 2103
Reputation: 49545
A few notes.
Here's a simple example.
The code below is licensed under : 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));
}
}
}
Upvotes: 2