最近用SocketChannel進行網絡編程比較多,中間也遇到了幾個問題,出現的bug也主要來自於對於ByteBuffer的使用不當。現在終於調通了,對ByteBuffer及Socket網絡編程也有了更深的認識,特此總結一下。
對於ByteBuffer主要需要注意的是幾個標志的含義:position,limit,capability,mark.幾個操作的影 響:flip(),clear(),rewind().還有就是在讀取或者寫入時,標志的變化,比如get()方法導致position加1.
SocketChannel采用的是非阻塞異步讀取流數據,在讀取的時候,通常是
- ByteBuffer.clear();
- SocketChannel.read(ByteBuffer);
如果流中有數據,就會把數據從position開始讀到ByteBuffer中,在讀取之前ByteBuffer的clear操作會把 position置為0,limit置為capability,也就是相當於清空了之前的內容,但是ByteBuffer中數組的內容在read之前是沒 有改變的.
read之后,通常就是開始從ByteBuffer中提取讀到的數據,如果你的數據是以自己定義的數據包的格式進行發送的,那你還需要判斷是否讀到 了數據包的結尾,因為對流數據本身來說是沒有結尾這一說的。在提取數據之前,要先把position放到開始讀取時的位置,把limit放到當前位置,所 以要flip一下,表示從position到limit的位置都是需要的數據。
- ByteBuffer.flip();
- while(ByteBuffer.hasRemaining()){
- byte c=ByteBuffer.get();
- if(b == PACKAGE_END){
- //you can return the package here
- }else{
- //you can append the byte here.like StringBuilder.append().
- }
- }
這樣以來也存在一個問題,當一次讀到的ByteBuffer不包含完整的數據包或者包含多個數據包.那么就需要在下一次繼續把這些包分拆出來.那么在讀取數據的代碼處就可以改為,這樣就把之前讀取到的未完整的包保留了下來:
- if(!ByteBuffer.hasRemaining){
- ByteBuffer.clear();
- SocketChannel.read(ByteBuffer);
- }
另外一個可能會用到的操作就是ByteBuffer.rewind(),他會把position置為0,limit保持不變,可以用於重復讀取一段數據.
ByteBuffer是nio中一個非常方便的工具.設計思想也非常值得借鑒.