Tomcatのサーブレットからapr_socket_sendfile()を使用する

このトピックでは、HTTPプロトコルを使用して、サーブレットからユーザーにファイルを転送するための小さいながら効果的な方法について説明します。 使用者:



もちろん、サーブレットファイルのレンダリングはパフォーマンスの点ではあまり良くありません。 まず、スクリプトをまったく使用せずに静的コンテンツをレンダリングするのが最善です。 しかし、それなしではできないこともあります。 次に、ほとんどの場合、データの戻りは次のようになります。

long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  1. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  2. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  3. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  4. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  5. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  6. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  7. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



  8. long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .



long writed = 0; byte [] buffer = new byte [BUFFER_LENGTH]; int readed = in .read(buffer, 0, BUFFER_LENGTH); while (readed != -1) { out .write(buffer, 0, readed); writed += readed; readed = in .read(buffer, 0, BUFFER_LENGTH); } * This source code was highlighted with Source Code Highlighter .





NIOに関する本を読んで顕微鏡を使用した後、これをもう少し効果的なツールに再作成できます。





  1. public static long transfer(File file、OutputStream out )throws IOException {
  2. return transfer(file、0、file.length()、 out );
  3. }
  4. パブリック 静的 ロング転送(ファイルファイル、 ロングポジション、 ロングカウント、
  5. OutputStream out )throws IOException {
  6. FileChannel in = new FileInputStream(file).getChannel();
  7. {
  8. long writed = in .transferTo(位置、カウント、チャンネル
  9. .newChannel( out ));
  10. 書かれたリターン ;
  11. } 最後に {
  12. in .close();
  13. }
  14. }
*このソースコードは、 ソースコードハイライターで強調表示されました。


ただし、サーバーのスタックトレースを慎重に調査した人は、TomcatのOutputStreamがチャネル経由の送信をサポートしていないことを知っています。



このアプローチの明らかな欠点は次のとおりです。



ただし、Apache Tomcatでは、サーブレットが(便利なインターフェイスを介して)Apache Portable Runtimeライブラリのapr_socket_sendfile関数を使用できます。 この関数は、ソケットへの入力ポインター、ファイル、および送信データの開始パラメーターと長さパラメーターを受け入れます(ファイル全体だけでなく、転送することもできます)。 この機能へのアクセスは、リクエスト属性(HttpServletRequest)を使用して行われます。 この機能を確認します。





  1. private static final String TOMCAT_SENDFILE_SUPPORT = "org.apache.tomcat.sendfile.support" ;
  2. 最終的なブールsendFileSupport = Boolean.TRUE.equals(リクエスト
  3. .getAttribute(TOMCAT_SENDFILE_SUPPORT));
*このソースコードは、 ソースコードハイライターで強調表示されました。




今なら:

  1. sendFileSupport == true
  2. コードの実行後すぐにファイルは削除されません
  3. ファイルサイズが2 GB未満


自分でファイルを転送する代わりに、Apache Tomcatに指示できます。





  1. private static final String TOMCAT_SENDFILE_FILENAME = "org.apache.tomcat.sendfile.filename" ;
  2. private static final String TOMCAT_SENDFILE_START = "org.apache.tomcat.sendfile.start" ;
  3. private static final String TOMCAT_SENDFILE_END = "org.apache.tomcat.sendfile.end" ;
  4. // Apache APRおよび/またはNIOを使用してファイルを転送します
  5. response.setBufferSize(1 << 18);
  6. request.setAttribute(TOMCAT_SENDFILE_FILENAME、file.getCanonicalPath());
  7. request.setAttribute(TOMCAT_SENDFILE_START、Long.valueOf(0));
  8. request.setAttribute(TOMCAT_SENDFILE_END、Long.valueOf(fileLength));
*このソースコードは、 ソースコードハイライターで強調表示されました。


2番目の制限は、サーブレットでの作業が終了した後にファイル転送プロセスが開始されるという事実によるものです。 3番目-明確ではありませんが、おそらくテストマシンに32ビットJVMと32ビットGentooがあるという事実(Tomcatは自分で2GB以上のファイルを与えたくありませんでした)。



その結果:



もちろん、本番システムでは、ファイル全体だけでなく部分的にも提供できるようにする必要があり、ユーザーが既にファイルを持っている可能性も考慮する必要があります(プロセスNotModifiedSince)。



さらなる研究のために




All Articles