简体   繁体   English

没有浏览器的Java Websocket客户端

[英]Java Websocket Client without a Browser

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. 我希望有一个HTML5 Web客户端(足够简单)和一个本地客户端(最好是Java),它们都可以连接到服务器。 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? 问题:有没有办法在没有浏览的情况下从本地Java客户端连接到websocket服务器? I have seen some browser wrappers in other languages that might make this possible. 我已经看到其他语言中的一些浏览器包装器可能使这成为可能。 If not, I am open to suggestions. 如果没有,我愿意接受建议。

Thanks. 谢谢。

You most certainly CAN utilize WebSockets from desktop applications in Java, outside the browser sandbox. 您当然可以在浏览器沙箱之外的Java中使用来自桌面应用程序的WebSockets。 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. 这背后的想法是您可以创建创建TCP连接的胖客户端,因此他们当然应该能够在这些TCP连接之上创建WebSocket连接。

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. 这样做的最新和最好的API之一是由Kaazing编写的,它认为WebSocket就像一个套接字,可以使用简单的“ws://”URI创建。

The API is discussed in detail on the Kaazing Gateway 5.0 Java WebSocket Documentation site . 在Kaazing Gateway 5.0 Java WebSocket文档站点上详细讨论了API。 You can download the plain Gateway from Kaazing here 您可以在这里从Kaazing下载普通网关

Create a websocket: 创建一个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对象:

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

To receive or consume messages, add WebSocket and WebSocketMessageReader objects: 要接收或使用消息,请添加WebSocket和WebSocketMessageReader对象:

    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.) (完全披露:我曾在Kaazing Corporation担任服务器工程师。)

You might also consider using JSR 356 - Java API for WebSocket . 您还可以考虑使用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. 它是Java EE 7的一部分,但客户端可以从普通的Java SE运行而不会出现任何问题。 There are multiple implementations available right now and following will work in all of them: 现在有多种实现可用,所有这些实现都可以使用:

programmatic API: 程序化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: 带注释的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. 这里有各种实现,基本上每个Java容器都有一个。 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/... ). 我正在开发Glassfish / WebLogic实现,它叫做Tyrus ,可以随意尝试(我们提供易于使用的所有功能,请参见http://search.maven.org / ... )。

Vert.x has a java websocket client: Vert.x有一个java websocket客户端:

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");
            }
        });

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: Netty是这项任务的不错选择,它是一个高性能的网络应用程序框架,它优雅地支持SSL,这里是来自netty github的netty websocket客户端示例

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();
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM