2012-01-28 97 views
8

我大部分都是使用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?我从来没有见过这样的例子。

回答

5

Jestan是正确的。就我而言,我有一个客户需要处理价格数据。我使用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<DataChangeListenter> listeners = new ArrayList<DataChangeListenter>(); 

    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); 
    } 
} 
+0

我试图按照你的指引来注册监听器,但我得到一个“不兼容的类型:字符串不能转换为DataChangeEvent”......出了什么问题?谢谢。 – Phobox 2016-03-09 09:10:31

1

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

这几乎是我想说的。您的处理程序中这是很容易的参数从那里传递到处理程序的PipelineFactory创建:

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或控制器。

+0

因此,例如,在http客户端示例中,结果仅转储到System.out。如果你有一个GUI,你必须把结果传递给?例如,它必须传递给处理程序不知道的JTextArea,或者可能是JDialog等。换句话说,JButton被按下,事件通过客户端调用服务器。你如何基本上将服务器的结果传递回JButton的调用方法。 – 2012-01-28 21:30:50

+0

要添加,因为JButton处理程序可能会在JTextArea中显示结果,也许它会是一个JDialog等。 – 2012-01-28 21:31:52

+1

您想使用回调(侦听器)来处理响应,如hotpottao asych模式http://hotpotato.biasedbit.com /,(这也是使用Netty),那么你必须在messageReceived中处理它:),我认为这种回调不是默认提供的,因为它们对于协议/应用程序来说更具体。 – 2012-01-29 05:21:57

相关问题