2012-10-07 113 views
0

我正在將Swing程序的業務邏輯移動到服務器上。桌面程序與服務器通信

什麼是最有效的溝通客戶端服務器和服務器客戶端的方式?

服務器將負責驗證,提取和存儲數據,所以程序將不得不頻繁通信。

+0

「最高效」的條款是什麼?帶寬,CPU時間,延遲,內存?或者只是最容易實現? – esaj

+0

我對[RMI](http://docs.oracle.com/javase/tutorial/rmi/index.html)的投票,本質上,通過網絡Objets – MadProgrammer

+0

延遲,我不希望用戶等待響應時間到每一個行動。 – Eleeist

回答

2

這取決於很多事情。如果你想有一個真正的答案,你應該清楚地瞭解到你的程序將做和你的

如果生產率的快速您的有效定義範圍,我所使用的方法「高效」的定義下什麼下降在過去涉及序列化將簡單的舊java對象向下發送到套接字。最近我發現,結合netty API,我能夠快速建立相當強大的客戶端/服務器通信原型。

膽量相當簡單;客戶端和服務器都使用管道中的ObjectDecoder和ObjectEncoder運行Netty。每個爲處理數據而設計的對象都有一個類。例如,一個HandshakeRequest類和HandshakeResponse類。

握手請求可能看起來像:

public class HandshakeRequest extends Message { 
    private static final long serialVersionUID = 1L; 
} 

和握手響應可能看起來像:

public class HandshakeResponse extends Message { 
    private static final long serialVersionUID = 1L; 
    private final HandshakeResult handshakeResult; 

    public HandshakeResponse(HandshakeResult handshakeResult) { 
     this.handshakeResult = handshakeResult; 
    } 

    public HandshakeResult getHandshakeResult() { 
     return handshakeResult; 
    } 
} 
在網狀

,當客戶端連接這樣的服務器會發送一個握手請求:

@Override 
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { 
    Channel ch = e.getChannel(); 
    ch.write(new HandshakeRequest(); 
} 

客戶端收到HandshakeRequest對象,但它需要一個告訴服務器剛剛發送了什麼樣的消息。爲此,可以使用Map<Class<?>, Method>。當你的程序運行時,它應該通過具有反射的類的方法進行迭代並將它們放置在地圖中。這裏是一個例子:

public HashMap<Class<?>, Method> populateMessageHandler() { 
    HashMap<Class<?>, Method> temp = new HashMap<Class<?>, Method>(); 
    for (Method method : getClass().getMethods()) { 
     if (method.getAnnotation(MessageHandler.class) != null) { 
      Class<?>[] methodParameters = method.getParameterTypes(); 
      temp.put(methodParameters[1], method); 
     } 
    } 
    return temp; 
} 

這個代碼將遍歷當前類和尋找標有註解@MessageHandler方法,然後看看該方法的第一個參數(該參數是一個對象,如public void handleHandshakeRequest(HandshakeRequest request))並將該類作爲關鍵字與實際方法放在地圖中,因爲它是值。

與此映射的地方,這是很容易獲得的消息,該消息直接發送到應處理消息的方法:

@Override 
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { 
    try { 
     Message message = (Message) e.getMessage(); 
     Method method = messageHandlers.get(message.getClass()); 
     if (method == null) { 
      System.out.println("No handler for message!"); 
     } else { 
      method.invoke(this, ctx, message); 
     } 
    } catch(Exception exception) { 
     exception.printStackTrace(); 
    } 
} 

有沒有真的沒有什麼東西留下來了。 netty處理所有雜亂的東西,允許我們輕鬆地來回發送序列化的對象。如果您決定不想使用netty,則可以將自己的協議包裝在java的Object Output Stream中。你將不得不整體做更多的工作,但溝通的簡單性保持不變。

0

這是一個有點很難說哪一種方法是在什麼樣的條件「最高效」,我不知道你的用例,但這裏有幾個選項:

最基本的方法是簡單地使用「原始」TCP套接字。好處是沒有什麼額外的網絡移動,你自己創建你的協議,後者也是一個缺點;您必須設計和實現您自己的通信協議,以及處理服務器端多個連接的基本框架(如果需要的話)。使用UDP套接字,你可能會節省一點延遲和帶寬(並不是很多,除非你使用類似移動數據的東西,你可能不會注意到TCP在延遲方面有任何不同),但網絡代碼有點難度; UDP套接字是「無連接的」,這意味着所有的客戶端消息將在同一個處理程序中結束,並且必須相互區分。如果服務器需要跟上客戶端狀態,那麼執行權利可能會有些麻煩。

MadProgrammer帶來了RMI(遠程方法調用),我個人從來沒有使用它,它似乎有點麻煩設置,但從長遠來看可能是相當不錯的實施方面。

也許最常見的一種方法是使用http進行通信,例如通過REST-interface來代替Web services。有多種框架(我個人比較喜歡Spring MVC)來幫助實現,但是現在學習一個新的框架可能已經超出了你的範圍。此外,複雜的http查詢或長時間的URL可能會讓你的帶寬多一點,但除非我們談論的是大量同時發生的客戶端,否則這通常不成問題(假設您將服務器運行在數據中心與100/100MBit連接等)。如果有的話,這可能是最容易擴展的解決方案,因爲有很多可用於Web服務器的負載平衡解決方案。

相關問題