2012-01-16 135 views
1

作爲我的協議的一部分,我希望客戶端在建立新連接時發送其版本號。我希望這是在一個單獨的處理程序中完成的,請耐心等待,因爲這可能是一個相當基本的問題,但我不知道該怎麼做。另一件事是我希望能夠通過連接(管道)來回發送POJO。此外,我很想添加一個身份驗證處理程序。無論如何,現在我得到了一些錯誤,我很確定這是因爲版本檢查沒有從管道中正確消化。Netty - 如何測試客戶端/服務器版本號

基本上我下面的代碼設置爲發送「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 
} 

所以基本上我想要的是版本號被傳遞和確認在通道作爲通信協議的一部分進行連接。全部在幕後自動完成。同樣,我很想通過這種方式傳遞認證機制。

我的確看到了一些代碼,看起來有點像我想要用安全聊天的例子,但我無法弄清楚。任何有關如何設置此代碼的幫助將非常感激。我知道我可以在一個大規模的處理程序中完成所有工作,但這是管道的關鍵,將其分解成符合邏輯的單元。

回答

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);這是爲了從任何進一步處理中刪除該處理程序。初始連接後不再需要它。感謝丹尼斯的提示。

結論

其餘的是多如我所料。關鍵是我沒有正確理解如何讀取緩衝區並傳遞信息。錯誤信息和例子不太清楚。只要您將Netty的POJO頻道添加到您的管道中,您就需要開始僅在對象中處理所有處理程序。我錯過了那一個。這些概念是正確的,只是我試圖從渠道讀取錯誤的數據。

另一個重要的提示是,如果初始連接後不需要處理程序,則從管道中刪除處理程序。我假設對於身份驗證處理程序也是如此。能夠在這裏得到確認真是太好了,但我必須在晚些時候弄清楚。

0

你沒有提到你看到的錯誤是什麼。

在任何情況下,我都不建議使用單獨的通道處理程序進行版本檢查。主要是因爲版本檢查應該只需要在連接建立時發生一次。另外,因爲我認爲渠道處理者最好留待處理傳輸層問題,例如將字節轉換爲pojos。

+0

我的想法是版本檢查的處理程序,用於身份驗證的處理程序,用於加密的處理程序以及用於實際業務邏輯的處理程序。 – 2012-01-16 20:52:33

+0

我最大的擔憂是,如果客戶端和服務器是不同的版本,並且您正在序列化POJO,那麼它將在反序列化時失敗。 – 2012-01-16 20:53:12

+0

這是一個很好的觀點。那麼你看到的錯誤是什麼? – 2012-01-17 16:15:09

0

我創建了一個簡單的例子:https://github.com/boldt/netty-examples/

它返回時,建立一個新的連接的版本號。它是在一個單獨的處理程序中完成的,它將在版本寫入通道後從管道中刪除。之後它是netty教程中的ECHO例子。

A telnet localhost 1234到服務器立即顯示版本。

像這樣,您可以在版本處理程序後面的管道中添加身份驗證處理程序。

+0

我真的很感謝你的回答,而你幾乎就在那裏。我只是想做些稍微不同的事情。基本上我希望客戶端將它的版本發送到服務器,然後服務器將發送異常或失敗。因此,服務器必須從客戶端接收版本號,然後繼續從通道讀取... – 2012-01-21 17:29:27

+0

另外,您是否可以讓客戶端在發送第二條消息後立即說出一個字符串,其中說「hello world」服務器能夠攝取。如果你這樣做,我會給你兩倍的賞金點,如果我可以! – 2012-01-21 17:44:54

+0

我只是想到了這一切,有一些概念錯誤。所以沒有必要經過一個例子的努力。不過,我很想在這個時候感謝你。這不是我正在尋找的東西,但是你提供的絕對是幫助類型,如果它已經達到了目標,那將是非常棒的:) – 2012-01-21 18:19:46

0

我認爲你想要的待辦事項可以通過添加一些自定義處理程序很容易歸檔。因此,對於版本檢查,您可以添加一個覆蓋channelConnected(....)的處理程序,並在那裏進行檢查。對於auth只是在重寫messageRecieved(....)方法的版本檢查後添加另一個處理程序。驗證完成後,您可以刪除管道的處理程序,並在您再次需要時將其添加回來。

作爲最後一個,BusinessLogic處理程序應該位於管道中。請注意,任何處理程序都會執行一些阻止操作,您應該考慮在其前面添加一個ExecutionHandler,以確保該工具線程不會被阻塞,從而使netty服務器不負責任。

相關問題