> Docs > WebSocket Server

WebSocket Server

A WebSocketServer needs to be attached to an HttpServer. The WebSocketServer must be created and configured before the HttpServer starts.

HttpServer httpServer = new HttpServer( req->HttpResponse.file(200, "/tmp/ws.test.html") );
httpServer.conf().trafficDump( System.out::print );

WebSocketHandler wsHandler = new MyWsHandler();
WebSocketServer wsServer = new WebSocketServer( httpServer, wsHandler );
wsServer.conf().trafficDump( System.err::print );


See WebSocketServerConf for config options.

Test Client

You can use this simple client for testing:


        <script type="text/javascript">
            window.onload = function()
                ws = new WebSocket("ws://localhost:8080");
                ws.onmessage = function(e){ log(e.data ); };
                ws.onclose   = function(e){ log("CLOSE"); };
                ws.onerror   = function(e){ log("ERROR"); };
            function log(s){ document.getElementById("log").innerHTML += s+"\n"; }
        <h1>WebSocket Test</h1>

        <input onkeydown="if(event.keyCode==13){ws.send(value);value='';}">

        <pre id="log"></pre>


Each WebSocketServer contains a WebSocketHandler that handles WebSocket handshakes. The WebSocketHandler interface contains a single abstract method

    Async<WebSocketResponse> handle(WebSocketRequest request)

For each handshake request, the handler generates either a Reject or an Accept response. For example,

public class MyWsHandler implements WebSocketHandler
    public Async<WebSocketResponse> handle(WebSocketRequest request)
        if( isBanned(request.ip()) )
            return WebSocketResponse.reject(403, "permission denied");
            return WebSocketResponse.accept( this::handleChannel );

    Async<Void> handleChannel(WebSocketChannel channel)

Note that in the default configuration, same-origin is enforced by the server before handle() is called.

If the handshake is accepted, the Accept response specifies a channelHandler. In the example above, the channel handler is this::handleChannel. A new WebSocketChannel is created after handshake and fed to the channel handler.


A WebSocketChannel contains methods to read and write WebSocketMessage.

    Async<WebSocketMessage> readMessage();

    Async<Long>  writeMessage(WebSocketMessage message);

For example, a simple echo server:

    Async<Void> handleChannel(WebSocketChannel channel)
        return AsyncIterator
            .forEach_( channel::readMessage, channel::writeMessage )
            .finally_( channel::close );

Note that if the client closes the channel gracefully, readMessage() action completes with WebSocketClose which is a subtype of End.

You may want to use the more convenient methods like readText(max) and writeText(chars)

    Async<Void> handleChannel(WebSocketChannel channel)
        AsyncIterator<String> inputs = ()->channel.readText(1000);
        return inputs
            .map( this::process )
            .forEach_( channel::writeText )
            .finally_( channel::close );
    String process(String input)
            case "time" : return Instant.now().toString();
            case "user" : return System.getProperty("user.name");
            default     : return "pardon?";

An example of a simple chat server:

    Async<Void> handleChannel(WebSocketChannel channel)
        allChannels.put(channel, "");

        return AsyncIterator
            .forEach_( ()->channel.readText(1000), this::broadcast )
            .finally_( ()->allChannels.remove(channel) )
            .finally_( channel::close );

    final ConcurrentHashMap<WebSocketChannel,String> allChannels = new ConcurrentHashMap<>();

    Async<Void> broadcast(String msg)
        for(WebSocketChannel channel : allChannels.keySet())
            channel.writeText(msg); // don't wait for write completion
        return Async.VOID;


A WebSocketMessage is a subtype of ByteSource. You can read an incoming message in streaming-style:

Async<WebSocketMessage> asyncMsg = channel.readMessage();
asyncMsg.then( msg->
    AsyncIterator.forEach( msg::read, System.out::println )

To create an outgoing message, see static methods in WebSocketMessage. For example, to send a file

ByteSource src = new FileByteSource("/tmp/abc.txt");
WebSocketMessage msg = WebSocketMessage.text( src );
channel.writeMessage( msg );

Hot Reload

Use HotWebSocketHandler to hot-reload the server app when source code changes.

Usually, a WebSocket app works together with an HTTP app; they share the same code and the same classloader. Therefore we want the two to share the same HotReloader.

HotReloader reloader = new HotReloader().onJavaFiles(SRC_DIR);

HotHttpHandler httpHandler = new HotHttpHandler(reloader, MyHttpHandler.class);

HotWebSocketHandler wsHandler = new HotWebSocketHandler(reloader, MyWsHandler.class);

After reloading, new WebSocket channels will be handled by the new handler instance; previous channels are still being handled by the old handler instance until they are closed. A client needs to reconnect (usually by refreshing browser window) to see the effect of reloading.