Netty - 如何测试客户端/服务器版本号

时间:2012-01-16 16:55:24

标签: java networking protocols netty channels

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

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

目前我有:

Client.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?

Server.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
}

基本上我想要的是当通道作为通信协议的一部分连接时,版本号被传递和验证。全部在幕后自动完成。同样,我也喜欢以这种方式传递身份验证机制。

我确实看到了一些看起来有点类似于我想要使用安全聊天示例的代码,但我无法弄明白。任何有关如何设置此代码的帮助将非常感激。我知道我可以在一个大型处理程序中完成所有操作,但这是管道的重点,将其分解为具有逻辑意义的单元。

4 个答案:

答案 0 :(得分:2)

我找到了解决方案!!!

有很多问题。

在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);,以便从任何进一步处理中删除该处理程序。初始连接后不再需要它。感谢Dennis的提示。

<强>结论

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

另一个重要提示是,如果在初始连接后不需要处理程序,则从管道中删除处理程序。我认为对于身份验证处理程序也是如此。在这里确认一下会很棒,但是我必须稍后再确定一下。

答案 1 :(得分:0)

你没有提到你所看到的错误。

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

答案 2 :(得分:0)

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

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

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

像这样你可以在版本处理程序后面的管道中添加一个身份验证处理程序。

答案 3 :(得分:0)

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

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