2013-04-02 48 views
0

我正在編寫我正在處理的應用程序的服務器組件。我正在使用NIO來處理網絡,但我正在努力找出一種處理閱讀的有效方法。客戶端應用程序可以將數據包發送到大小差別很大的服務器。它可能是一個100字節的文本消息,或500千字節的圖片,服務器需要能夠處理這些數據包。通常,我會創建一個足以包含最大可能數據包的緩衝區,但在此應用程序的情況下,這意味着我可能必須爲每個客戶端提供緩衝區大小爲的大小,並且這會吞噬內存。在和我的朋友討論之後,我已經決定要處理這個問題,就好像我使用舊的IO一樣。這意味着我將爲每個數據包分配一個新的緩衝區,緩衝區的容量恰好是傳入數據包的長度。我的包結構如下:Java:使用NIO讀取可變大小的數據包

[INT] [長度]
[字節] [操作碼]
[字節...] [有效載荷]

我的方法是具有兩個單獨的緩衝器:一個容量爲4的緩衝區讀取長度,另一個緩衝區將不斷用不同的容量重新初始化 - 數據包的長度。這裏是我想出的代碼:

User user = (User) selectionKey.attachment(); 
SocketChannel socketChannel = user.getSocketChannel(); 
ByteBuffer readBuffer = user.getReadBuffer(); 
ByteBuffer lengthBuffer = user.getLengthBuffer(); 
/* 
* Read as many packets as possible. 
*/ 
while (true) { 
    /* 
    * Read the length if it has not been read yet. 
    */ 
    if (lengthBuffer.hasRemaining()) { 
    socketChannel.read(lengthBuffer); 
    /* 
    * If the length could not be read, stop reading and wait for 
    * more data to arrive. 
    */ 
    if (lengthBuffer.hasRemaining()) { 
     break; 
    } 
    } else { 
    /* 
    * Create a read buffer if one has not been created for the 
    * incoming packet. 
    */ 
    if (readBuffer == null) { 
     lengthBuffer.flip(); 
     user.setReadBuffer(ByteBuffer.allocate(lengthBuffer 
      .getInt())); 
    } 
    /* 
    * Attempt to read the packet. 
    */ 
    socketChannel.read(readBuffer); 
    /* 
    * If the packet was not completely read, then stop reading 
    * altogether because all of the data has not been received yet. 
    */ 
    if (readBuffer.hasRemaining()) { 
     break; 
    } else { 
     /* 
     * Otherwise, handle the data and prepare the buffers for 
     * the next packet read. 
     */ 
     readBuffer.flip(); 
     user.handleData(); 
     user.setReadBuffer(null); 
     lengthBuffer.clear(); 
    } 
    } 
} 

而且我看到了一些問題。首先,我有時會在行socketChannel.read(readBuffer)上發生NullPointerException。除此之外,這個解決方案似乎並不乾淨。我覺得代碼中有太多的邏輯,這似乎有問題。任何人都可以提供一些修改或我的代碼或完全不同的方法嗎?我會很感激。謝謝。

在附註中,任何人都可以在評論中發佈一個很好的方法將Eclipse中的代碼粘貼到這裏並正確格式化嗎?您可能會注意到,我使用代碼按鈕,但縮進仍然不正確。

回答

0

我會建議你使用netty框架。因爲它已經有了解決這些問題的機制。看看this

+0

嗯...我認爲這會爲我節省一些時間使用圖書館。 –

-1

您需要將連接視爲字節流。 TCP中沒有這樣的數據包。服務器可能會向您發送100個字節,然後500個字節,但它可能一次到達接收方,一次一個字節,或者介於兩者之間。所以如果你的協議中有不同的消息,第一個要求是你可以自己分割它們,就好像你是從一個文件而不是一個套接字讀取它們一樣。直到你將它建立到你的協議中,這個問題纔不可能解決。

+0

我確實以同樣的方式構建了我的所有數據包。我知道,一旦我讀了長度,我需要讀取長度的字節量。一旦讀取,我知道接下來的4個字節讀取將是另一個長度等等。我遇到的問題實際上是編寫高效且有效的代碼來完成該過程。 –