2012-01-28 123 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

相關問題