【问题标题】:Netty - How to test for client/server version numbersNetty - 如何测试客户端/服务器版本号
【发布时间】:2012-02-11 14:16:54
【问题描述】:

作为我协议的一部分,我希望客户端在建立新连接时发送其版本号。我希望在管道中的单独处理程序中完成此操作,因此请耐心等待,因为这可能是一个相当基本的问题,但我不知道该怎么做。另一件事是我希望能够通过连接(管道)来回发送 POJO。另外我很想添加一个身份验证处理程序。无论如何,现在我遇到了某种错误,我很确定这是因为版本检查没有从管道中正确消化。

基本上,我下面的代码设置为发送“Hello World”,服务器在建立连接后检查版本后打印出来。至少在理论上,实际上这并不完全有效;)

目前我有:

客户端.java

public static void main(String[] args)
{
    ...

    // Set up the pipeline factory.
    bootstrap.setPipelineFactory(new ChannelPipelineFactory() 
    {
        @Override
        public ChannelPipeline getPipeline() throws Exception 
        {
            return Channels.pipeline(
                    new ObjectEncoder(),
                    new ObjectDecoder(),
                    new VersionClientHandler(),
                    new BusinessLogicClientHandler());
        }
    });     

    ...

    // The idea is that it will all be request and response. Much like http but with pojo's. 
    ChannelFuture lastWriteFuture = channel.write("Hello world".getBytes());

    if (lastWriteFuture != null) 
    {
        System.out.println("waiting for message to be sent");
           lastWriteFuture.awaitUninterruptibly();
    }

    ...
}

VersionClientHandler.java

public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
{
    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_STRING_LENGTH);
    versionBuffer.writeBytes("v123.45a".getBytes());
    // If I understand correctly, the next line says use the rest of the stream to do what you need to the next Handler in the pipeline?
    Channels.write(ctx, e.getFuture(), versionBuffer);  
}

BusinessLogicClientHandler.java

Not really doing anything at this point. Should it?

服务器.java

public static void main(String[] args)
{
    ...

    public ChannelPipeline getPipeline() throws Exception 
    {
        return Channels.pipeline(
                new ObjectEncoder(),
                new ObjectDecoder(),
                new VersionServerHandler(),
                new BusinessLogicServerHandler());
    }

    ...
}

VersionServerHandler.java

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_NUMBER_MAX_SIZE);
    System.out.println("isReadable - messageReceived: " + versionBuffer.readable()); // returns false???
    // Basically I want to read it and confirm the client and server versions match.
    // And if the match fails either send a message or throw an exception
    // How do I also pass on the stream to the next Handler? 
}

BusinessLogicServerHandler.java

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    e.getMessage();
    byte[] message = (byte[])e.getMessage(); // "Hello World" in byte[] from Client.java
}

所以基本上我想要的是在作为通信协议的一部分连接通道时传递并验证版本号。所有这些都是在幕后自动完成的。同样,我很想以这种方式通过身份验证机制。

我确实看到了一些看起来有点像我想要对安全聊天示例执行的代码,但我无法真正弄清楚。任何有关如何设置此代码的帮助将不胜感激。我知道我可以在一个大型处理程序中完成所有工作,但这就是管道的重点,将其分解为合乎逻辑的单元。

【问题讨论】:

    标签: java networking protocols netty channels


    【解决方案1】:

    你没有提到你看到的错误是什么。

    无论如何,我不建议使用单独的通道处理程序进行版本检查。主要是因为版本检查应该只需要在首次建立连接时发生一次。也因为我认为通道处理程序最好留在处理传输层问题,例如将字节转换为 pojo。

    【讨论】:

    • 我的想法是版本检查处理程序、身份验证处理程序、加密处理程序和实际业务逻辑处理程序。
    • 我最担心的是,如果客户端和服务器是不同的版本,并且你正在序列化 pojo,那么它会在反序列化时失败。
    • 各种。没有什么是真正有效的。存在一些概念问题,而不仅仅是编码问题。
    【解决方案2】:

    我创建了一个简单的例子:https://github.com/boldt/netty-examples/

    建立新连接时返回版本号。它在一个单独的处理程序中完成,该处理程序将在版本写入通道后从管道中删除。然后是netty教程中的ECHO示例。

    发给服务器的telnet localhost 1234 会立即显示版本。

    像这样,您可以将身份验证处理程序添加到版本处理程序后面的管道中。

    【讨论】:

    • 非常感谢您的回答,您就快到了。我只是想做一些稍微不同的事情。基本上我希望客户端将它的版本发送到服务器,然后服务器会发回异常或失败。所以服务器必须从客户端摄取版本号,然后继续从频道读取...
    • 另外,你能否让客户端在之后立即发送第二条消息,比如一个字符串,上面写着“hello world”,服务器可以接收。如果你这样做了,如果可以的话,我会给你双倍的赏金!!
    • 我只是想通了,有一些概念上的错误。所以没有必要通过一个例子的努力。不过,我真的很感谢你的时间。这不是我想要的,但你提供的绝对是那种如果能达到目标会很棒的帮助:)
    【解决方案3】:

    我认为通过添加一些自定义处理程序可以轻松归档您想要做的事情。因此,对于版本检查,您可以添加一个覆盖 channelConnected(....) 的处理程序并在那里进行检查。对于身份验证,只需在版本检查之后添加另一个处理程序,它会覆盖 messageRecieved(....) 方法。身份验证完成后,您可以从管道中删除处理程序,并在再次需要时将其添加回来。

    BusinessLogic Handler 应该作为最后一个位于管道中。请注意,您的任何处理程序都会执行一些阻塞操作,您应该考虑在其前面添加一个 ExecutionHandler 以确保 ioworker 线程不会被阻塞,从而使 netty 服务器不负责任。

    【讨论】:

      【解决方案4】:

      我找到了解决办法!!!

      有很多问题。

      在 VersionClientHandler 上,新代码为:

      public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
      {
          String verison = "v123.45a";
      
          ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_STRING_LENGTH);
          versionBuffer.writeBytes(version.getBytes());
          e.getChannel().write(version);
      }
      

      请注意最后一行 e.getChannel().write(version); 而不是 Channels.write(ctx, e.getFuture(), versionBuffer); 我不确定原因。 事实上,我正要开始研究为什么我有 ChannelBuffers 代码,因为它似乎没有做任何事情......

      在 VersionServerHandler.java 我现在有:

      public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
      {
          String versionCheck = (String)e.getMessage();
          System.out.println("VersionServerHandler - " + versionCheck);
          ctx.getPipeline().remove(VersionServerHandler.class);
      }
      

      请注意,我不再读取缓冲区,我只是执行e.getMessage() 并转换为正确类型的对象。在此之上,我添加了ctx.getPipeline().remove(VersionServerHandler.class);,它可以从任何进一步的处理中删除该处理程序。初始连接后不再需要它。感谢丹尼斯的提示。

      结论

      其余的和我预期的差不多。关键是我没有正确理解如何读取缓冲区和传递信息。并且错误消息和示例不是很清楚。一旦您将来自 Netty 的 POJO 通道添加到您的管道,您就需要开始只处理对象,用于所有处理程序。我错过了那个。这些概念是正确的,只是我试图从错误的通道中读取数据的方式。

      另一个重要提示是,如果在初始连接后不需要处理程序,则从管道中删除它们。我假设身份验证处理程序也是如此。很高兴在这里得到确认,但我必须稍后再弄清楚。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-11
        • 1970-01-01
        • 2013-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多