Netty – 如何在客户端获取服务器响应

我主要在那里使用Netty,但是一个概念仍在暗指我,我在教程中找不到任何东西等等。 首先,我确实理解Netty是异步的,但是必须有一种方法让客户端调用服务器并能够获得超出处理程序的响应。 让我解释一下。

我有一个客户,如下图所示。 请注意,我理解它是自助的,并且每次调用都建立了一个新连接,这就是为了使示例更小,更简洁。 请忽略这一事实。

Client.java

// ServerResponse is a result from the server, in this case // a list of users of the system (ignore that each time it's all bootstrapped). public User[] callServerForInformationFromGUIWidget() { ClientBootstrap bootstrap = new ClientBootstrap(...); bootstrap.setPipelineFactory(...); ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); Channel channel = future.awaitUninterruptibly().getChannel(); // Where request is a POJO sent to the server, // with a request such as get me a list of users RequestPojo request = new RequestPojo(requestUserListCommand); ChannelFuture lastWriteFuture = channel.write(request); if(lastWriteFuture != null) lastWriteFuture.awaitUninterruptibly(); } 

现在我了解如何获取服务器上的数据,并重新启动结果。 唯一的问题是如何在客户端处理它? 是的clientHandler类可以执行以下操作:

ClientHandler.java

 @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { User[] users = (User[])e.getMessage(); } 

问题是客户端代码如何实际获得该结果? 所有示例都类似于聊天服务,其中事件会触发客户端上不等待响应的其他内容。 甚至我发现的http客户端示例也缺乏这个。 整体文档非常好,但缺乏如何进行回调。 无论如何,在这种情况下,我需要客户端从服务器获取响应,并根据结果它将执行它所需的。

换句话说,我如何编写客户端来执行以下操作:

IdealClient.java

 // ServerResponse is a result from the server, in this case // a list of users of the system. public User[] callServerForInformationFromGUIWidget() { ... RequestPojo request = new RequestPojo(requestUserListCommand); ChannelFuture lastWriteFuture = channel.write(request); if(lastWriteFuture != null) lastWriteFuture.awaitUninterruptibly(); User[] users = resultFromCallToServer(); performSomeAction(users); } 

因为处理程序不知道谁在寻找答案,或者谁问了问题。 如果它是在处理程序中完成的,那么如何?

回到我对这些示例的评论,http客户端(和处理程序)示例只是将结果转储到System.out。 如果你有一个GUI,你如何将结果从你的请求传递到GUI? 我从未见过这方面的任何例子。

杰斯坦是对的。 在我的情况下,我有一个客户需要处理价格刻度数据。 我使用Antlr进行解析。 我在我的解析器中激活了我的事件,但在我的情况下,我的协议是基于字符串的。 下面是一个没有Antlr的例子,我在你的情况下传递了String消息,它可能是用户。

 //----------------- Event -------------- public class DataChangeEvent { private String message; public DataChangeEvent(String message) { this.message = message; } public String getMessage() { return message; } } //----------------- Listener -------------- public interface DataChangeListenter { public void dataChangeEvent(DataChangeEvent event); } //----------------- Event Handler that fires the dataChange events -------------- // This class needs to be static since you need to register all your classes that want to be notified of data change events public class DataChangedHandler { private static List listeners = new ArrayList(); public static void registerDataChangeListener(DataChangeListenter listener) { listeners.add(listener); } public static void fireDataChange(DataChangeEvent dataChangeEvent) { for(DataChangeListenter listenter : listeners) { listenter.dataChangeEvent(dataChangeEvent); } } } //----------------- Example class that implements the listener and registers itself for events -------------- public class ProcessMessage implements DataChangeListenter { public ProcessMessage() { DataChangedHandler.registerDataChangeListener(this); } public void dataChangeEvent(DataChangeEvent event) { //Depending on your protocal, I use Antlr to parse my message System.out.println(event.getMessage()); } } //---------------- Netty Handler ----------- public class TelnetClientHandler extends SimpleChannelHandler { private static final Logger logger = Logger.getLogger(TelnetClientHandler.class.getName()); @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { String message = (String) e.getMessage(); DataChangedHandler.fireDataChange(message); } } 

您必须使用messageReceived()在Handler中处理它。 我不确定你的问题到底是什么。 我的猜测是你对一个根据请求发生变化的请求做出了回应? 也许是对你正在做的事情的具体描述,它必须知道它来自哪个请求。 您可以做的一件事是将一个长生命对象传递给知道未完成请求的处理程序,它可以在收到响应时匹配响应。 管道工厂方法可以将对管理器类型对象的引用传递给处理程序。

这几乎就是我想说的。 您的处理程序是在PipelineFactory中创建的,它很容易从那里将参数传递给Handler:

  bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.nulDelimiter())); pipeline.addLast("decoder", new XMLDecoder() ); pipeline.addLast("encoder", new XMLEncoder() ); // notice here I'm passing two objects to the Handler so it can // call the UI. pipeline.addLast("handler", new MyHandler(param1, param2)); return pipeline; } }); 

创建管道时,您将在新连接时添加处理程序。 只需传递一个或多个允许它与UI或控制器通信的对象。