web-dev-qa-db-ja.com

Java.net.SocketExceptionを修正する方法:壊れたパイプ?

私はパラメータを投稿するためにpostメソッドを使用してurlを呼び出すのにApache commons httpクライアントを使用しています、そしてそれはめったに以下のエラーを投げています。

Java.net.SocketException: Broken pipe
        at Java.net.SocketOutputStream.socketWrite0(Native Method)
        at Java.net.SocketOutputStream.socketWrite(SocketOutputStream.Java:92)
        at Java.net.SocketOutputStream.write(SocketOutputStream.Java:136)
        at Java.io.BufferedOutputStream.write(BufferedOutputStream.Java:105)
        at Java.io.FilterOutputStream.write(FilterOutputStream.Java:80)
        at org.Apache.commons.httpclient.methods.ByteArrayRequestEntity.writeRequest(ByteArrayRequestEntity.Java:90)
        at org.Apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.Java:499)
        at org.Apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.Java:2114)
        at org.Apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.Java:1096)
        at org.Apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.Java:398)

誰かがこの例外を引き起こしている原因とそれをデバッグする方法を提案できますか?

141
Mani

これは以下によって引き起こされます。

  • ほとんどの場合、相手側がすでにそれを閉じているときに接続に書き込みます。
  • あまり一般的ではありませんが、ピアは、最後に保留中のデータをすべて読み取らずに接続を閉じます。

そのため、どちらの場合も、アプリケーションプロトコルの定義や実装が不十分です。

ここでは説明しませんが、接続を適切に閉じるのではなく、ピアが意図的にリセットしてリセットする3つ目の理由があります。

73
user207421

私たちの場合は、アプリサーバーで負荷テストを実行しているときにこれを経験しました。問題は、JVMが使い果たされたため、JVMにメモリを追加する必要があることです。これで問題は解決しました。

JVMで使用可能なメモリーを増やしたり、これらのエラーが発生したときにメモリー使用量をモニターしたりしてください。

28
Dave

SocketException:パイプが壊れています。コードが接続から読み書きしている間に「相手側」(クライアントまたはサーバー)が接続を閉じることが原因です。

これは、アプリケーション制御外のクライアントまたはサーバーからトラフィックを受信するクライアント/サーバーアプリケーションでは非常に一般的な例外です。たとえば、クライアントはブラウザです。ブラウザがAjax呼び出しをしたり、ユーザーが単にページやブラウザを閉じたりすると、すべての通信が予期せず中断される可能性があります。基本的には、相手側がアプリケーションを終了させるたびにこのエラーが表示されますが、予期していませんでした。

アプリケーションでこの例外が発生した場合は、IO(Input/Output)がある場所でコードを確認し、try/catchブロックでラップしてこのIOExceptionをキャッチする必要があります。それで、あなたがこの半有効な状況をどう処理したいかを決めるのはあなた次第です。

あなたの場合、あなたがまだ制御を持っている最も早い場所はHttpMethodDirector.executeWithRetryへの呼び出しです - それで呼び出しがtry/catchブロックでラップされていることを確認して、あなたが適当であるかどうかそれを処理します。

デバッグ/トレースレベル以外でSocketException-Broken Pipe固有のエラーをログに記録しないことを強くお勧めします。そうでなければ、これはログをいっぱいにすることによってDOS(サービス拒否)攻撃の形式として使用することができます。この一般的なシナリオに対して、アプリケーションを強化してネガティブテストします。

7
AndyGee

開いているストリームと接続はすべて適切に閉じる必要があるので、次回urlConnectionオブジェクトを使用しようとしたときにエラーになることはありません。例として、次のコード変更は私のためのエラーを修正しました。

前:

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();

後:

OutputStream os = urlConnection.getOutputStream();
OutputStream out = new BufferedOutputStream(os);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Some text");
bw.close();
out.close();
os.close(); // This is a must.
4
Murali Mohan

FTPサーバーを介してデータのダウンロード機能を実装しましたが、そのダウンロードを再開しているときにも同じ例外が見つかりました。この例外を解決するには、常に前のセッションから切断し、クライアントの新しいインスタンスとサーバーとの新しい接続を作成する必要があります。これと同じ方法がHTTPClientにも役立ちます。

1
Naeem Ahmad

上記の回答は、このJava.net.SocketException: Broken pipeの理由を示しています。もう一方の端が接続を閉じました。遭遇したときに何が起こったのか経験を共有したいと思います。

  1. クライアントのリクエストでは、Content-Typeヘッダがリクエストの本文よりも誤って大きく設定されています(実際には本文がまったくありませんでした)。
  2. tomcatソケットの一番下のサービスは、そのサイズの本文データを待っていました(httpはTCPになっています。
  3. 60秒が経過すると、Tomcatはタイムアウト例外をスローします。Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception Java.net.SocketTimeoutException: null
  4. タイムアウト例外のため、クライアントはステータスコード500の応答を受け取ります。
  5. クライアントが接続を閉じる(応答を受け取るため)。
  6. クライアントが閉じたため、TomcatはJava.net.SocketException: Broken pipeをスローします。

時々、Tomcatは壊れたpip例外を投げません、タイムアウト例外が接続を閉じるので、そのような違いが私も混乱させるのです。

0
Tiina

問題は、デプロイされたファイルが正しいRMIメソッドで更新されていないことです。 RMIインターフェイスにパラメータが更新されたか、クライアントにはないデータ構造が更新されたことを確認します。または、RMIクライアントに、サーバーのバージョンと異なるパラメータがないということです。

これは単なる推測です。サーバーアプリケーションのクラスファイルを再デプロイして再テストしたところ、 "Broken pipe"の問題は解決しました。

0

原因は、リモートピアがそのソケットを閉じること(たとえばクラッシュ)であるため、たとえば、彼にデータを書き込もうとすると、これが発生します。それを解決するには、(try catch)試行の間のソケット操作に対する読み書きを保護してから、失われた接続ケースをcatchに管理します(接続の更新、プログラムの停止など)。

 try {
      /* your code */
 } catch (SocketException e) {
      e.printStackTrace();
      /* insert your failure processings here */
 }