Java Websocket Client without a Browser
Asked Answered
J

4

11

I am working on a project that requires real-time interaction between users. I want to have a HTML5 web client (simple enough) and also a local client (preferably Java) with both being able to connect to the server. I have done some research and have not found a conclusive answer to whether or not the local client can connect to the server without a browser.

Question: Is there any way to connect from a local Java client to a websocket server without a browse? I have seen some browser wrappers in other languages that might make this possible. If not, I am open to suggestions.

Thanks.

Jeri answered 17/1, 2014 at 19:32 Comment(1)
Possible Duplicate: #7257568Magneton
P
9

You might also consider using JSR 356 - Java API for WebSocket. It is part of Java EE 7, but client can be run from plain Java SE without any issues. There are multiple implementations available right now and following will work in all of them:

programmatic API:

    final WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();

    Session session = webSocketContainer.connectToServer(new Endpoint() {
        @Override
        public void onOpen(Session session, EndpointConfig config) {
            // session.addMessageHandler( ... );
        }
    }, URI.create("ws://some.uri"));

annotated API:

public static void main(String[] args) throws IOException, DeploymentException {
    final WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
    webSocketContainer.connectToServer(MyEndpoint.class, URI.create("ws://some.uri"));
}

@ClientEndpoint
public static class MyEndpoint {

    // text
    @OnMessage
    void onMessage(Session session, String message) {
        // ...
    }

    // binary
    @OnMessage
    void onMessage(Session session, ByteBuffer message) {
        // ...
    }

    // @OnClose, @OnOpen, @OnError
}

please see linked page for further details (full specification).

There are various implementations out here, basically every Java container has one. I am working on Glassfish/WebLogic implementation and its called Tyrus, feel free to try it out (we provide easy to use all in one bundle, see http://search.maven.org/...).

Peavey answered 20/1, 2014 at 10:20 Comment(0)
V
8

You most certainly CAN utilize WebSockets from desktop applications in Java, outside the browser sandbox. The thinking behind this is that you can create thick clients that create TCP connections, so of course they should be able to create WebSocket connections on top of those TCP connections.

One of the newest and best APIs for doing so is written by Kaazing, taking the point of view that a WebSocket is just like a socket and can be created using simple "ws://" URIs.

The API is discussed in detail on the Kaazing Gateway 5.0 Java WebSocket Documentation site. You can download the plain Gateway from Kaazing here

Create a websocket:

    import com.kaazing.net.ws.WebSocket;
    import com.kaazing.net.ws.WebSocketFactory;

    wsFactory = WebSocketFactory.createWebSocketFactory();
    ws = wsFactory.createWebSocket(URI.create("ws://example.com:8001/path"));
    ws.connect(); // This will block or throw an exception if failed.

To send messages, add a WebSocketMessageWriter object:

    WebSocketMessageWriter writer = ws.getMessageWriter();
    String text = "Hello WebSocket!";
    writer.writeText(text);   // Send text message

To receive or consume messages, add WebSocket and WebSocketMessageReader objects:

    wsFactory = WebSocketFactory.createWebSocketFactory();
    ws = wsFactory.createWebSocket(URI.create("ws://example.com:8001/path"));
    ws.connect(); // This will block or throw an exception if failed.

    WebSocketMessageReader reader = ws.getMessageReader();
    WebSocketMessageType type = null; // Block till a message arrives
      // Loop till the connection goes away
      while ((type =  reader.next()) != WebSocketMessageType.EOS) {
        switch (type) { // Handle both text and binary messages
          case TEXT:
            CharSequence text = reader.getText();
            log("RECEIVED TEXT MESSAGE: " + text.toString());
            break;
          case BINARY:
            ByteBuffer buffer = reader.getBinary();
            log("RECEIVED BINARY MESSAGE: " + getHexDump(buffer));
            break;
        }
    }

(Full Disclosure: I used to work at Kaazing Corporation as a server engineer.)

Vigilance answered 18/1, 2014 at 6:37 Comment(0)
B
3

Vert.x has a java websocket client:

VertxFactory.newVertx()
    .createHttpClient()
    .setHost("localhost")
    .setPort(8080)
    .connectWebsocket("/ws", new Handler<WebSocket>() {

            @Override
            public void handle(final WebSocket webSocket) {

                // Listen
                webSocket.dataHandler(new Handler<Buffer>() {
                    @Override
                    public void handle(Buffer buff) {
                        log.info("Received {}", buff.toString());
                    }
                });

                // Publish
                webSocket.writeTextFrame("Heya");
            }
        });
Beefsteak answered 1/3, 2014 at 16:22 Comment(0)
A
3

Netty is a good choice for such task, it's a high performance network application framework and it supports SSL elegantly, here is netty websocket client example from netty github:

public final class WebSocketClient {

static final String URL = System.getProperty("url", "ws://127.0.0.1:8080/websocket");

public static void main(String[] args) throws Exception {
    URI uri = new URI(URL);
    String scheme = uri.getScheme() == null? "ws" : uri.getScheme();
    final String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
    final int port;
    if (uri.getPort() == -1) {
        if ("ws".equalsIgnoreCase(scheme)) {
            port = 80;
        } else if ("wss".equalsIgnoreCase(scheme)) {
            port = 443;
        } else {
            port = -1;
        }
    } else {
        port = uri.getPort();
    }

    if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) {
        System.err.println("Only WS(S) is supported.");
        return;
    }

    final boolean ssl = "wss".equalsIgnoreCase(scheme);
    final SslContext sslCtx;
    if (ssl) {
        sslCtx = SslContextBuilder.forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
    } else {
        sslCtx = null;
    }

    EventLoopGroup group = new NioEventLoopGroup();
    try {
        // Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00.
        // If you change it to V00, ping is not supported and remember to change
        // HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline.
        final WebSocketClientHandler handler =
                new WebSocketClientHandler(
                        WebSocketClientHandshakerFactory.newHandshaker(
                                uri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders()));

        Bootstrap b = new Bootstrap();
        b.group(group)
         .channel(NioSocketChannel.class)
         .handler(new ChannelInitializer<SocketChannel>() {
             @Override
             protected void initChannel(SocketChannel ch) {
                 ChannelPipeline p = ch.pipeline();
                 if (sslCtx != null) {
                     p.addLast(sslCtx.newHandler(ch.alloc(), host, port));
                 }
                 p.addLast(
                         new HttpClientCodec(),
                         new HttpObjectAggregator(8192),
                         WebSocketClientCompressionHandler.INSTANCE,
                         handler);
             }
         });

        Channel ch = b.connect(uri.getHost(), port).sync().channel();
        handler.handshakeFuture().sync();

        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            String msg = console.readLine();
            if (msg == null) {
                break;
            } else if ("bye".equals(msg.toLowerCase())) {
                ch.writeAndFlush(new CloseWebSocketFrame());
                ch.closeFuture().sync();
                break;
            } else if ("ping".equals(msg.toLowerCase())) {
                WebSocketFrame frame = new PingWebSocketFrame(Unpooled.wrappedBuffer(new byte[] { 8, 1, 8, 1 }));
                ch.writeAndFlush(frame);
            } else {
                WebSocketFrame frame = new TextWebSocketFrame(msg);
                ch.writeAndFlush(frame);
            }
        }
    } finally {
        group.shutdownGracefully();
    }
}
}

public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {

private final WebSocketClientHandshaker handshaker;
private ChannelPromise handshakeFuture;

public WebSocketClientHandler(WebSocketClientHandshaker handshaker) {
    this.handshaker = handshaker;
}

public ChannelFuture handshakeFuture() {
    return handshakeFuture;
}

@Override
public void handlerAdded(ChannelHandlerContext ctx) {
    handshakeFuture = ctx.newPromise();
}

@Override
public void channelActive(ChannelHandlerContext ctx) {
    handshaker.handshake(ctx.channel());
}

@Override
public void channelInactive(ChannelHandlerContext ctx) {
    System.out.println("WebSocket Client disconnected!");
}

@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
    Channel ch = ctx.channel();
    if (!handshaker.isHandshakeComplete()) {
        handshaker.finishHandshake(ch, (FullHttpResponse) msg);
        System.out.println("WebSocket Client connected!");
        handshakeFuture.setSuccess();
        return;
    }

    if (msg instanceof FullHttpResponse) {
        FullHttpResponse response = (FullHttpResponse) msg;
        throw new IllegalStateException(
                "Unexpected FullHttpResponse (getStatus=" + response.status() +
                        ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
    }

    WebSocketFrame frame = (WebSocketFrame) msg;
    if (frame instanceof TextWebSocketFrame) {
        TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
        System.out.println("WebSocket Client received message: " + textFrame.text());
    } else if (frame instanceof PongWebSocketFrame) {
        System.out.println("WebSocket Client received pong");
    } else if (frame instanceof CloseWebSocketFrame) {
        System.out.println("WebSocket Client received closing");
        ch.close();
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    if (!handshakeFuture.isDone()) {
        handshakeFuture.setFailure(cause);
    }
    ctx.close();
}
}
Alphanumeric answered 18/7, 2017 at 11:14 Comment(1)
An answer should stand on it's own. Please expand this answer a bit.Education

© 2022 - 2024 — McMap. All rights reserved.