我正在編寫我正在處理的應用程序的服務器組件。我正在使用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中的代碼粘貼到這裏並正確格式化嗎?您可能會注意到,我使用代碼按鈕,但縮進仍然不正確。
嗯...我認爲這會爲我節省一些時間使用圖書館。 –