Java.nio中socketChannle.write()返回0的簡易解決方案__socket

來源:互聯網
上載者:User

之前使用Java IO實現了一個檔案傳送的小demo,今天打算採用java nio重寫一遍。

首先,用nio寫好檔案接收端後,採用原先的IO程式測試,發現並不存在問題。

接著,寫檔案發送端,ByteBuffer大小設定為1024,發送端分多次傳送檔案片段,在接受端組合形成檔案,近而寫入檔案系統。

程式寫好後:

1,用一個2K的檔案測試,發現並無問題

2,用一個44k的檔案測試,發現接收端只接受到23k的內容;


調試發現發送端中 SocketChannel.write()迴圈中在發送23k左右的內容後就一直返回0


問題分析:在socket 編程中,對於write(),內容受頻寬節流設定不可能瞬間發送出去,應該有緩衝區。在普通阻塞IO中,當緩衝區滿了就阻塞了,而對於非阻塞的socket,緩衝區滿了就立即返回0。

解決方案:Java nio的預設緩衝區為8k。將其用setSendBufferSize設定為32*1024後,稍大點的檔案就能正常發送了。但對於大小為十幾兆的檔案估計還是有困難。經尋找可以在write返回0的時候,將OP_WRITE註冊進selector,然後對可寫性進行判斷,當selector檢測到可寫時,繼續傳送檔案片段。發送完畢後登出OP_WRITE。

但我覺得與其用這種方法還不如用Java普通的IO。阻塞IO CPU耗費還比NIO小很多。


對於大檔案的傳輸將緩衝區的容量增大,只能是杯水車薪。原因在於這個緩衝區的最大容量是有限制的。

造成緩衝區滿的根本原因,是接收端的問題,假設將檔案從用戶端發給伺服器,用戶端很可能是在一個while迴圈發送讀取到的檔案內容。

這存在很多問題:

1,頻寬,資料不可能秒發,在頻寬很小的情況下,write()的寫資料速度要比緩衝區的發送速度快的多。可以將緩衝區比作一個水桶,這個水桶底部有一個漏水孔,而write就是一台抽水機,不停的往水桶送水,水桶裡的水肯定溢出。


2,伺服器接收端的處理速度。一般的伺服器都存在多個線程,而且對於傳進來的資料還需要進行很多的處理,如解碼,重排等等。而用戶端就只執行一個任務或者是線程:不停的發送資料。這是個典型的生產者消費者的問題,在普通阻塞IO中由於存在阻塞,並不存在問題。而在NIO中,由於讀寫非阻塞,write()在緩衝區已滿的情況下無法寫入,返回0,造成資料丟失

這裡還有一個解決的辦法就是偵測ByteBuffer.remanning(),在還有資料的時候重新發送,直到發送出去。另為保證CPU,迴圈內加Sleep。睡眠時間和緩衝區大小存在一定的關係,緩衝區設定得大,就可以選擇一個較大的睡眠時間,根本目的是保證發送緩衝區一直有資料,不存在空的情況。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.