【问题标题】:How to get Netty to serve / accept websocket from web-app served on different server ('node') on different port如何让 Netty 服务/接受来自不同端口上不同服务器(“节点”)上的 web 应用程序的 websocket
【发布时间】:2019-02-16 16:16:30
【问题描述】:

我正在使用 Angular 7 webapp 中的 websocket。这个想法是让“节点”为网络应用程序提供服务 - 例如地址:

http://localhost:4200/

和 websocket 在另一个由 Netty / Java 应用程序服务的地址和端口上。

在网络应用程序上,我导航到 websocket 的页面。有一个文本框用于输入 websocket 的地址和按钮:'Connect' - 将我们连接到 web-socket 服务器。例如测试这个地址可以正常工作:

ws://echo.websocket.org          // works - we get a response
or
ws://echo.websocket.org:80       // works - we get a response

相反,我想让 Netty 服务器为 websocket 提供服务。我启动服务器 - 服务地址:

http://localhost:8081/

并且运行良好。 (我可以从单独的浏览器窗口和服务器在此地址和端口上提供的 websocket 页面进行连接)。

但现在我想从我的网络应用程序连接到 Netty 服务器 - localhost:4200/。所以,我为套接字连接提供了这个地址;

ws://localhost:8081/

然后点击“连接”。

Netty 服务器对此日志做出反应(所有行同时出现):

Feb 16, 2019 7:26:20 AM io.netty.handler.logging.LoggingHandler channelRead
INFO: [id: 0xfd77a1f7, L:/0:0:0:0:0:0:0:0:8081] READ: [id: 0x24ad1bc1, L:/127.0.0.1:8081 - R:/127.0.0.1:51928]
Feb 16, 2019 7:26:20 AM io.netty.handler.logging.LoggingHandler channelReadComplete
INFO: [id: 0xfd77a1f7, L:/0:0:0:0:0:0:0:0:8081] READ COMPLETE
Websocke channel Active:[id: 0x24ad1bc1, L:/127.0.0.1:8081 - R:/127.0.0.1:51928]
Websocke channel Inactive:[id: 0x24ad1bc1, L:/127.0.0.1:8081 ! R:/127.0.0.1:51928]
Websocke channel Unregistered:[id: 0x24ad1bc1, L:/127.0.0.1:8081 ! R:/127.0.0.1:51928]

这可能意味着通信正常,但是,Netty 不接受并且正在关闭 websocket。

这些是我在 Netty 管道中的处理程序:

    new HttpServerCodec());
    new HttpObjectAggregator(65536));
    new WebSocketServerCompressionHandler());
    new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
              // Next handler serves index.html page
              //   ... extends SimpleChannelInboundHandler<FullHttpRequest>
              //       @Override
              //      protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
    new WebSocketIndexPageHandlerA1(WEBSOCKET_PATH));
              // Next handler handles websocket communication
              //   ... extends SimpleChannelInboundHandler<WebSocketFrame>
              //       @Override
              //      protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
    new WebSocketFrameHandlerA1());

我们如何让 Netty 接受这个 websocket 请求并将流向下传递到我的最后一个处理程序 - web socket 消息处理程序 - WebSocketFrameHandlerA1 以便它可以回复 websocket 客户端 - 无论它们来自哪里?

【问题讨论】:

    标签: websocket netty


    【解决方案1】:

    这个问题有一个相当直接和合乎逻辑的答案。我们只需要为我们的 Netty 管道配备与来自客户端的预期流量(HTTP/Websocket 等)相对应的处理程序。

    所以,如果我们尝试使用以下方式连接到 Netty:

    ws://localhost:8081/
    

    服务器会收到一个初始的 HTTP 请求 - 像这样:

    GET / HTTP/1.1
    Host: localhost:8081
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Sec-WebSocket-Version: 13
    Origin: http://localhost:4200
    Sec-WebSocket-Extensions: permessage-deflate
    Sec-WebSocket-Key: XVXVXS%GDDD+lDfDS==
    Connection: keep-alive, Upgrade
    Cookie: _ga=GA1.1.1146780314.5634479786
    Pragma: no-cache
    Cache-Control: no-cache
    Upgrade: websocket
    Connection : keep-alive, Upgrade
    Upgrade : websocket
    

    我们必须确保管道中有正确的处理程序,以处理初始 HTTP 请求,然后升级/切换到 websocket 处理程序。在这种情况下,初始管道可以像这样简单:

    pipeline.addLast("httpServerCodec", new HttpServerCodec());
    pipeline.addLast("httpHandler", new HttpServerHandler());
    

    HttpServerHandler 中进一步包括:

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
    
            if (msg instanceof HttpRequest) {
    
                HttpRequest httpRequest = (HttpRequest) msg;
                HttpHeaders headers = httpRequest.headers();
    
                if (headers.get(HttpHeaderNames.CONNECTION).toUpperCase().contains("UPGRADE") &&
                headers.get(HttpHeaderNames.UPGRADE).toUpperCase().contains("WEBSOCKET")) {
    
                    // Replace the HTTP handler with a websocket handler
                    // in the existing pipeline to handle WebSocket Messages
                    ctx.pipeline().replace(this, "websocketHandler", new WebSocketHandler());
                    //Do the Handshake to upgrade connection from HTTP to WebSocket protocol
                handleHandshake(ctx, httpRequest);
            }
            ...
          }
    

    在您的 websocket 处理程序中插入客户端和服务器之间的数据交换逻辑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多