【问题标题】:Java Websocket Client without a Browser没有浏览器的 Java Websocket 客户端
【发布时间】:2014-01-17 19:32:08
【问题描述】:

我正在开展一个需要用户之间实时交互的项目。我想要一个 HTML5 Web 客户端(足够简单)和一个本地客户端(最好是 Java),两者都能够连接到服务器。我做了一些研究,没有找到关于本地客户端是否可以在没有浏览器的情况下连接到服务器的结论性答案。

问题:有没有什么方法可以在不浏览的情况下从本地 Java 客户端连接到 websocket 服务器?我已经看到一些其他语言的浏览器包装器可能使这成为可能。如果没有,我愿意接受建议。

谢谢。

【问题讨论】:

标签: java html websocket client


【解决方案1】:

您也可以考虑使用 JSR 356 - Java API for WebSocket。它是 Java EE 7 的一部分,但客户端可以从纯 Java SE 运行而不会出现任何问题。目前有多种实现可用,以下将适用于所有实现:

程序化 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"));

带注释的 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
}

请查看链接页面了解更多详情(完整规格)。

这里有各种实现,基本上每个 Java 容器都有一个。我正在研究 Glassfish/WebLogic 实现及其称为 Tyrus,请随时试用(我们提供易于使用的所有功能,请参阅 http://search.maven.org/...)。

【讨论】:

    【解决方案2】:

    您当然可以在浏览器沙箱之外的 Java 桌面应用程序中使用 WebSocket。这背后的想法是您可以创建创建 TCP 连接的胖客户端,因此它们当然应该能够在这些 TCP 连接之上创建 WebSocket 连接。

    Kaazing 编写了用于执行此操作的最新和最佳 API 之一,他认为 WebSocket 就像一个套接字,可以使用简单的“ws://”URI 创建。

    API 详细讨论on the Kaazing Gateway 5.0 Java WebSocket Documentation site。您可以从 Kaazing here 下载普通网关

    创建一个网络套接字:

        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.
    

    要发送消息,请添加一个 WebSocketMessageWriter 对象:

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

    要接收或消费消息,请添加 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;
            }
        }
    

    (完全披露:我曾在 Kaazing Corporation 担任服务器工程师。)

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        Netty 是一个很好的选择,它是一个高性能的网络应用框架,它优雅地支持 SSL,这里是来自 netty github 的netty websocket client example:

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

        【讨论】:

        • 答案应该是独立的。请扩大这个答案。
        猜你喜欢
        • 2020-11-18
        • 2011-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-13
        • 1970-01-01
        • 2020-09-23
        • 2022-06-27
        相关资源
        最近更新 更多