Backend API. Server-side code: this runs in a Codename One backend, not in the app on the device.

public final class WebSocketSession

  1. Object
  2. WebSocketSession

One websocket connection: the decoder that turns bytes into messages, and the handle an application sends through.

Why the decoder is a state machine rather than a loop over whole frames

A frame arrives in as many reads as the network chooses. The header may be split across two of them, the mask key across four, and a 10MB payload across thousands – so every piece of state that spans a read boundary lives in a field here: how much of the current payload is still owed, how far into the mask key the next byte lands, whether a message is open and which opcode started it, and how far a UTF-8 character got. pump consumes whatever has arrived and stops cleanly when it wants more, which is what lets the same decoder be driven by a blocking loop on a virtual thread and by one reactor turn on a pool worker.

Why this buffer is its own

The HTTP read path borrows a per-host-thread array and parses in place. That is free for a request, which is read, served and written without stopping – and exactly wrong for a websocket, which stops between every message by design. A borrowed buffer held across a park has to be copied at every park, so this class owns its buffer from the moment of upgrade and never touches Conn.buffer again. See HttpServer.tryUpgrade.

Why sending takes a lock and checks a flag three times

Broadcast is the normal reason to run a websocket server, so a send can come from any thread. Two writes to one descriptor would interleave frames, hence writeLock. Worse, the descriptor can be closed under a sender and its NUMBER reused immediately – so dead is set before the close and checked on the way in, after registering as a writer, and again under the lock. A handle whose connection has gone is inert rather than dangerous.

Methods

public long getId()A number unique within this process, for logging and for keying a registry.
public String getPath()The path the client upgraded on, with no query string.
public String getQuery()The query string, or null when there was none.
public String getHandshakeHeader(String name)A header from the handshake request, case-insensitively.
public String getSubprotocol()The negotiated subprotocol, or null when none was.
public boolean isOpen()Whether this connection is still usable.
public Object getAttachment()
public void setAttachment(Object value)Anything the endpoint wants to keep per connection.
public void sendText(String value) throws IOException
public void sendBinary(byte[] value, int offset, int length) throws IOException
public void sendBinary(byte[] value) throws IOException
public void sendPing(byte[] payload, int offset, int length) throws IOException
public void sendPong(byte[] payload, int offset, int length) throws IOException
public void close()A normal close, code 1000, no reason.
public void close(int code, String reason)Starts the closing handshake.
public void abort()Drops the connection with no closing handshake.

Inherited methods

Method details

getId

public long getId()
A number unique within this process, for logging and for keying a registry.

getPath

public String getPath()
The path the client upgraded on, with no query string.

getQuery

public String getQuery()
The query string, or null when there was none.

getHandshakeHeader

public String getHandshakeHeader(String name)

A header from the handshake request, case-insensitively.

Snapshotted at upgrade, because the Request it came from stops being valid the moment the handshake finishes.

getSubprotocol

public String getSubprotocol()
The negotiated subprotocol, or null when none was.

isOpen

public boolean isOpen()
Whether this connection is still usable.

getAttachment

public Object getAttachment()

setAttachment

public void setAttachment(Object value)
Anything the endpoint wants to keep per connection.

sendText

public void sendText(String value) throws IOException

sendBinary

public void sendBinary(byte[] value, int offset, int length) throws IOException

sendBinary

public void sendBinary(byte[] value) throws IOException

sendPing

public void sendPing(byte[] payload, int offset, int length) throws IOException

sendPong

public void sendPong(byte[] payload, int offset, int length) throws IOException

close

public void close()
A normal close, code 1000, no reason.

close

public void close(int code, String reason)

Starts the closing handshake.

Sends a Close frame and then waits for the peer’s, which is what lets the last message already in flight arrive. A peer that never answers is shed by the connection’s read timeout rather than held forever.

abort

public void abort()
Drops the connection with no closing handshake. For a peer already lost.