ほぼ 2 日間のグーグル検索と、ウェブ全体で見つけたいくつかの異なる可能性を試した後、最終的に答えが得られることを期待して、ここでこの質問をしています。
まず、私がやりたいことは次のとおりです。
単一サーバー上の複数のクライアント間で大量の大きなファイルを交換する目的で、クライアントとサーバー アプリケーションを開発しています。クライアントは純粋なJava (JDK 1.6) で開発され、Web アプリケーションはGrails (2.0.0) で開発されています。
クライアントの目的は、ユーザーが大量の大きなファイル (通常はそれぞれ約 2GB) を交換できるようにすることであるため、アップロードを再開できるように実装する必要があります。つまり、ユーザーがアップロードを停止および再開できるようにする必要があります。いつでも。
これが私がこれまでにしたことです:
私は実際にやりたいことをやり、大きなファイルをサーバーにストリーミングすることができましたが、生のソケットを使用してアップロードを一時停止および再開することもできました。サーバーに通常のリクエストを (Apache の HttpClient ライブラリを使用して) 送信し、サーバーから自由に使用できるポートを送信してもらい、サーバーで ServerSocket を開き、クライアントからその特定のソケットに接続します。
ここに問題があります:
実際、これには少なくとも 2 つの問題があります。
- これらのポートは自分で開くので、開いているポートと使用中のポートを自分で管理する必要があります。これは非常にエラーが発生しやすいです。
- 私は実際、膨大な量の (同時) 接続を管理する Grails の機能を回避しています。
最後に、私が今やるべきことと問題は次のとおりです。
上で述べた問題は容認できないので、Grails にこだわりながら、Java の URLConnection/HttpURLConnection クラスを使用することになっています。
サーバーへの接続と単純なリクエストの送信はまったく問題なく、すべて正常に機能しました。ストリーム (クライアントでは接続の OutputStream、サーバーでは要求の InputStream) を使用しようとしたときに問題が発生しました。クライアントの OutputStream を開いてデータを書き込むのは、とても簡単です。しかし、リクエストの InputStream からの読み取りは、そのストリームが常に emptyであるように見えるため、私には不可能に思えます。
サンプルコード
サーバー側(Groovy コントローラー)の例を次に示します。
def test() {
InputStream inStream = request.inputStream
if(inStream != null) {
int read = 0;
byte[] buffer = new byte[4096];
long total = 0;
println "Start reading"
while((read = inStream.read(buffer)) != -1) {
println "Read " + read + " bytes from input stream buffer" //<-- this is NEVER called
}
println "Reading finished"
println "Read a total of " + total + " bytes" // <-- 'total' will always be 0 (zero)
} else {
println "Input Stream is null" // <-- This is NEVER called
}
}
これは私がクライアント側(Javaクラス)で行ったことです:
public void connect() {
final URL url = new URL("myserveraddress");
final byte[] message = "someMessage".getBytes(); // Any byte[] - will be a file one day
HttpURLConnection connection = url.openConnection();
connection.setRequestMethod("GET"); // other methods - same result
// Write message
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes(message);
out.flush();
out.close();
// Actually connect
connection.connect(); // is this placed correctly?
// Get response
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = null;
while((line = in.readLine()) != null) {
System.out.println(line); // Prints the whole server response as expected
}
in.close();
}
前述したように、問題はrequest.inputStream
常に空の InputStream が生成されるため、そこから何も読み取れないことです (もちろん)。しかし、それはまさに私がやろうとしていることなので(ファイルをストリーミングしてサーバーにアップロードし、InputStream から読み取ってファイルに保存することができます)、これはかなり残念です。
さまざまな HTTP メソッド、さまざまなデータ ペイロードを試し、コードを何度も再配置しましたが、問題を解決できなかったようです。
私が見つけたいもの
もちろん、私の問題の解決策を見つけたいと思っています。ヒント、コード スニペット、ライブラリの提案など、何でも大歓迎です。たぶん、私はそれをすべて間違っていて、まったく別の方向に進む必要があるのかもしれません.
では、サーバー側でポートを手動で開かずに、Java クライアントから Grails Web アプリケーションへのかなり大きな (バイナリ) ファイルの再開可能なファイル アップロードを実装するにはどうすればよいでしょうか?