2016-01-22 114 views
5

我正在爲我的客戶端到服務器應用程序創建登錄服務器。服務器到客戶端的服務器身份驗證 - 單線程

基本上有5個服務器,並且所有這些服務器都連接到一個登錄服務器。

客戶端可以連接到這5臺服務器中的任何一臺,但需要使用用戶名和密碼進行認證。身份驗證應該在登錄服務器中完成,並且登錄服務器應該向實際的服務器返回應答,以便將答案返回給客戶端。

因此,它像:

客戶端 - >服務器 - >登錄服務器 - >服務器 - >客戶端(響應代碼)

現在,我使用的Netty和它的NIO,它不是thread-每個客戶端。現在,爲了與NIO進行身份驗證,我們必須等待來自登錄服務器的響應,這可能需要一段時間並延遲其他希望登錄的客戶端,實際上,您不能等待NIO的解答。所以我想到了一個想法,我該如何讓它工作。我的想法是在不同的線程上運行請求,並使用onResponse(String key, int responseCode)方法處理事件,然後將客戶端的頻道放入帶有生成密鑰的地圖中,這樣我們就可以知道響應屬於哪個人。所以當我們進行身份驗證時,我們會發送密鑰和用戶數據。

但我覺得這是一個壞的方法,有一個更有效的方法來做到這一點。有任何想法嗎?

+0

AFAIK netty支持使用每個連接的線程來阻塞NIO。請注意,NIO的* default *行爲是阻塞操作,直到最近只有Socket支持非阻塞操作作爲選項。 –

+0

在多服務器環境中,使用地圖保留通道時會被破壞。 – eg04lt3r

+0

只是一個建議,因爲你要求更好的方法來做到這一點 - 如果你使用Java,你可能需要查看websockets,例如html 5 + http(s)。然後,您爲每個客戶端模型獲得一個線程,使用加密進行身份驗證對您的應用程序是透明的,並且您可以獲得NIO的所有功能,而無需部署最終客戶端。 – MuffinMan

回答

2

假設你有所有系統的完全控制:

分配一個ID爲服務器中的每個客戶端連接。然後,當您需要驗證用戶時,請將此連接ID包含在從服務器到登錄服務器的請求中,然後返回而無需等待登錄服務器的答覆。

在未來的某個時間,您的服務器將接收來自登錄服務器的登錄響應。如果登錄響應包含客戶端連接ID - 使用該ID來查找從服務器到客戶端的連接,並將該答覆轉發回客戶端。

1

這是我做到的。

設置

創建頻道包裝類,這樣就可以識別哪個通道屬於哪個客戶端。

public class CustomChannel implements Channel { 

    private final Channel channel; 
    private final String clientId; 

    ... 
} 

創建匹配的客戶端的通道自定義ChannelMatcher:

public class CustomChannelMatcher implements ChannelMatcher { 
    private final String clientId; 

    public CustomChannelMatcher(String clientId) { 
     this.clientId = clientId; 
    } 

    @Override 
    public boolean matches(Channel channel) { 
     if (channel instanceof CustomChannel) { 
      return clientId.equals(((CustomChannel) channel).getClientId()); 
     } 
     return false; 
    } 

    ... 
} 

處理請求

在客戶端的處理程序,使用通道組來跟蹤客戶的渠道。

ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 

... 

channelGroup.add(new CustomChannel(ctx.channel(), clientId)); 

// send request to another server without blocking 

處理響應

在您的服務器處理器,使用CustomChannelMatcher以符合客戶的渠道。

// when the server responds sometimes later 

channelGroup.writeAndFlush(responseMessage, 
    new CustomChannelMatcher(clientId)); 

上面的代碼將找到一個匹配的客戶端通道並將消息寫入它。

1

您很擔心會阻塞NIO工作線程,但您會旋轉另一個線程來執行登錄。無論如何,你只是再使用一個線程。所以在你的服務器中爲http定義更多的線程並完成它。除非您預計有超過100個併發登錄,否則這裏沒有問題。

NIO被高估;操作系統在調度線程和上下文切換方面非常出色,比在java中使用asyn apis做後空翻更好。等待線程不消耗CPU。

0

我知道你說你是在Netty上。我只需要說一些關於servlet api的東西(如果你可以使用它):

僅供參考,這是servlet api 3.0+的問題,它允許您在AsynContext中執行完全相同的工作。不要開玩笑,仔細閱讀servlet 3.0,最好是javaone youtube演示文稿和教程,即使PDF規範比javadoc更好。

如果你甚至想在servletinputstream/servletoutputstream上執行NIO,你可以使用servlet api 3.1來實現(儘管有點牽扯)。 javaone演示文稿(2014我認爲)非常棒。

相關問題