Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Netty-如何测试客户端/服务器版本号_Java_Networking_Protocols_Netty_Channels - Fatal编程技术网

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

Java Netty-如何测试客户端/服务器版本号,java,networking,protocols,netty,channels,Java,Networking,Protocols,Netty,Channels,作为协议的一部分,我希望客户端在建立新连接时发送其版本号。我希望这是在管道中的一个单独的处理程序中完成的,所以请容忍我,因为这可能是一个相当基本的问题,但我不确定如何做。另一件事是,我希望能够通过连接(管道)来回发送POJO。我还想添加一个身份验证处理程序。不管怎么说,现在我遇到了一些错误,我很确定这是因为版本检查没有从管道中得到正确的消化 基本上,我下面的代码设置为发送“Hello World”,当连接建立后,服务器在检查版本后打印出来。至少在理论上,在现实中这不太管用;) 目前我有: Cli

作为协议的一部分,我希望客户端在建立新连接时发送其版本号。我希望这是在管道中的一个单独的处理程序中完成的,所以请容忍我,因为这可能是一个相当基本的问题,但我不确定如何做。另一件事是,我希望能够通过连接(管道)来回发送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);  
}
Not really doing anything at this point. Should it?
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? 
}
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    e.getMessage();
    byte[] message = (byte[])e.getMessage(); // "Hello World" in byte[] from Client.java
}
BusinessLogicClientHandler.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);  
}
Not really doing anything at this point. Should it?
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? 
}
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    e.getMessage();
    byte[] message = (byte[])e.getMessage(); // "Hello World" in byte[] from Client.java
}
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 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);  
}
Not really doing anything at this point. Should it?
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? 
}
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    e.getMessage();
    byte[] message = (byte[])e.getMessage(); // "Hello World" in byte[] from Client.java
}
BusinessLogicServerHandler.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);  
}
Not really doing anything at this point. Should it?
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? 
}
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    e.getMessage();
    byte[] message = (byte[])e.getMessage(); // "Hello World" in byte[] from Client.java
}
所以基本上我想要的是,当通道作为通信协议的一部分连接时,版本号被传递和验证。所有这些都是在幕后自动完成的。类似地,我希望通过这种方式传递身份验证机制


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

您没有提到您看到的错误是什么


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

我创建了一个简单的示例:

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

发送到服务器的
telnet localhost 1234
会立即显示版本


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

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


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

我找到了解决方案

有许多问题

在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);
}
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    String versionCheck = (String)e.getMessage();
    System.out.println("VersionServerHandler - " + versionCheck);
    ctx.getPipeline().remove(VersionServerHandler.class);
}
注意最后一行,
e.getChannel().write(version)
而不是
Channels.write(ctx,e.getFuture(),versionBuffer)
在VersionServerHandler.java上,我现在有:

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);
}
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通道添加到管道中,您就需要开始只处理所有处理程序的对象。我错过了那个。概念是正确的,只是我试图从通道读取数据的方式是错误的


另一个大技巧是,如果在初始连接后不需要处理程序,则从管道中删除它们。我假设对于身份验证处理程序也是如此。如果能在这里确认,那就太好了,但我以后必须弄清楚这一点。

我的想法是版本检查处理程序、身份验证处理程序、加密处理程序和实际业务逻辑处理程序。我最担心的是,如果客户机和服务器是不同的版本,而您正在序列化pojo,然后它将在反序列化时失败。所有类型。什么都没用。这里有一些概念性的问题,而不仅仅是编码问题。我真的很感谢你的回答,你几乎做到了。我只是想做一些稍微不同的事情。基本上,我希望客户端将其版本发送到服务器,然后服务器将返回异常或失败。因此,服务器必须从客户端接收版本号,然后继续从通道读取…此外,您能否让客户端在服务器能够接收到的“hello world”字符串之后立即发送第二条消息。如果你这样做了,我会给你双倍的赏金如果我能!!我只是想明白了,有一些概念上的错误。因此,没有必要通过一个例子来说明。不过我还是要谢谢你