java nio socketChannel read__Java

來源:互聯網
上載者:User

當socketChannel為阻塞方式時(預設就是阻塞方式)read函數,不會返回0,阻塞方式的socketChannel,若沒有資料可讀,或者緩衝區滿了,就會阻塞,直到滿足讀的條件,所以一般阻塞方式的read是比較簡單的,不過阻塞方式的socketChannel的問題也是顯而易見的。這裡我結合基於NIO 寫ftp伺服器調試過程中碰到的問題,總結一下非阻塞情境下的read碰到的問題。注意:這裡的情境都是基於用戶端以阻塞socket的方式發送資料。

1、read什麼時候返回-1

read返回-1說明用戶端的資料發送完畢,並且主動的close socket。所以在這種情境下,你需要關閉socketChannel並且取消key,最好是退出當前函數。注意,這個時候服務端要是繼續使用該socketChannel進行讀操作的話,就會拋出“遠程主機強迫關閉一個現有的串連”的IO異常。

2、read什麼時候返回0

其實read返回0有3種情況,一是某一時刻socketChannel中當前(注意是當前)沒有資料可以讀,這時會返回0,其次是bytebuffer的position等於limit了,即bytebuffer的remaining等於0,這個時候也會返回0,最後一種情況就是用戶端的資料發送完畢了,這個時候用戶端想擷取服務端的反饋調用了recv函數,若服務端繼續read,這個時候就會返回0。

總結:當用戶端發送的是檔案,而且大小未知的情況,服務端如何判斷對方已經發送完畢。如單純的判斷是否等於0,可能會導致用戶端發送的資料不完整。所以,這裡加了一個檢測0出現次數的判斷,來判斷用戶端是否確實是資料發送完畢了,當然這個方法是比較笨拙的方法,大家若有更好的方法,期待大家給我答案。

網上也有類似的建議,比如自訂協議,在資料頭部帶上檔案大小等。

注意:這裡有一個問題就是通過這種while迴圈讀取的方式,實際上它只有一次NIO事件通知,而且在這個處理過程中,其他事件就得不到及時處理,除非while結束。


服務端的代碼(用戶端發送的資料大小未知)

<pre name="code" class="java">package com.myftpnio.handler;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import com.myftpnio.server.FtpNioServer;public class ClientHandler implements NioHandler {private SocketChannel sc;@SuppressWarnings("unused")private Selector selector;private ByteBuffer buf = ByteBuffer.allocate(1024);private long sum = 0;private static int count_zore = 0;public ClientHandler(SocketChannel sc, Selector selector) {this.sc = sc;this.selector = selector;}@Overridepublic void execute(SelectionKey key) {// TODO Auto-generated method stubif (key.isReadable()) {try {while(true) {buf.clear();int n = sc.read(buf);if (n > 0) {sum += n;System.out.println("sum=" + sum + " n=" + n + " " + FtpNioServer.ByteBufferToString(buf));} else if (n == 0) {if (count_zore++ < FtpNioServer.MAX) {continue;} else {key.interestOps(SelectionKey.OP_WRITE);break;}} else if (n == -1) {System.out.println("client close connect");sc.close();key.cancel();return;}}} catch (IOException e) {//處理捕獲到的IO異常System.out.println(e.getMessage());try {sc.close();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}key.cancel();return;}}if (key.isWritable()) {try {String ret = "hello " + sc.socket().getRemoteSocketAddress().toString();ByteBuffer send = ByteBuffer.wrap(ret.getBytes());sc.write(send);key.cancel();sc.close();FtpNioServer.connum--;count_zore = 0;} catch (Exception e) {e.printStackTrace();}}}}
 
 
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.