web-dev-qa-db-ja.com

サーブレットでのバイナリデータの送受信

HttpServletRequest.getOutputStream()HttpServletResponse.getInputStream()を使用して、バイナリデータ要求を受信して​​応答するJavaサーブレットを作成しようとしています。これは、このサーブレットがHTTP POST接続を介して応答するSilverlightクライアントからリクエストを送信するプロジェクト用です。とりあえず、サーブレットをテストするために、Silverlightよりも使い慣れたJavaでクライアントを実装しています。

問題は、私のテストプロジェクトでは、サーブレットクライアントからデータをバイト配列として送信し、同じ長さのバイト配列を受信することを期待していることです。受信しないだけで、代わりに1バイトを取得します。したがって、私が間違っているところを教えてくれることを期待して、関連するコードスニペットをここに投稿し、関連する参考文献を提供してさらに役立つことを願っています。

だからここに行きます。

clientサーブレットは、フロントエンドとして使用するフォームを使用して、非常に単純なHTMLページからのPOSTリクエストを処理します。 JSPなどの使用についてはあまり心配していませんが、代わりにサーブレット間通信を機能させることに重点を置いています。

// client HttpServlet invokes this method from doPost(request,response)
private void process(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
  String firstName = (String) request.getParameter("firstname");
  String lastName = (String) request.getParameter("lastname");
  String xmlRequest = "<MyRequest><Person><Name Firstname=\""+firstName+"\" Lastname=\""+lastName+"\" /></Person></MyRequest>";

  OutputStream writer = null;
  InputStream reader = null;
  try {
    URL url = new URL("http://localhost:8080/project/Server");
    URLConnection conn = url.openConnection();
    conn.setDoInput(true);
    conn.setDoOutput(true);

    writer = conn.getOutputStream();
    byte[] baXml = xmlRequest.getBytes("UTF-8");
    writer.write(baXml, 0,baXml.length);
    writer.flush();
    // perhaps I should be waiting here? how?

    reader = conn.getInputStream();
    int available = reader.available();
    byte[] data = new byte[available];
    reader.read(data,0,available);
    String xmlResponse = new String(data,"UTF-8");

    PrintWriter print = response.getWriter();
    print.write("<html><body>Response:<br/><pre>");
    print.write(xmlResponse);
    print.write("</pre></body></html>");
    print.close();

  } finally {
    if(writer!=null)
      writer.close();
    if(reader!=null)
      reader.close();
  }
}

serverサーブレットはHTTP POSTリクエストを処理します。これは、上記のテスト目的でクライアントサーブレットからリクエストを受信することによって行われますが、将来的には他の言語(具体的には、Silverlight)のクライアントにも使用する予定です。

// server HttpServlet invokes this method from doPost(request,response)
private void process(HttpServletRequest request, HttpServetResponse response)
throws ServletException, IOException {
  ServletInputStream sis = null;
  try {
    sis = request.getInputStream();
    // maybe I should be using a BufferedInputStream 
    // instead of the InputStream directly?
    int available = sis.available();
    byte[] input = new byte[available];
    int readBytes = sis.read(input,0,available);
    if(readBytes!=available) {
      throw new ServletException("Oops! readBytes!=availableBytes");
    }

    // I ONLY GET 1 BYTE OF DATA !!! 
    // It's the first byte of the client message, a '<'.
    String msg = "Read "+readBytes+" bytes of "
                 +available+" available from request InputStream.";
    System.err.println("Server.process(HttpServletRequest,HttpServletResponse): "+msg);
    String xmlReply = "<Reply><Message>"+msg+"</Message></Reply>";
    byte[] data = xmlReply.getBytes("UTF-8");
    ServletOutputStream sos = response.getOutputStream();
    sos.write(data, 0,data.length);
    sos.flush();
    sos.close();

  } finally {
    if(sis!=null)
      sis.close();
  }
}

これまで、BufferInputStreamsを使用する代わりにバイト配列に固執してきました。これは、たとえば、を使用するかどうかをまだ決定していないためです。データを送信するため、またはバイナリデータをそのまま送信する場合はBase64でエンコードされた文字列。

前もって感謝します。

9
jbatista

私が考えることができる1つのことは、あなたがrequest.getInputStream().available()バイトだけを読んでいて、それからあなたがすべてを持っていると決定しているということです。 documentation によると、available()はブロックせずに読み取ることができるバイト数を返しますが、これが実際に全体であることが保証されているかどうかについては言及されていません。入力ストリームのコンテンツであるため、そのような保証は行われていないと想定する傾向があります。

EOFで無期限にブロックするリスクを冒さずに、データがなくなったとき(おそらく、リクエストにContent-Lengthが役立つ可能性があります)を見つける方法がわかりませんが、からすべてのデータを読み取るまでループを試みます。入力ストリーム。その理論をテストするために、ストリームのさらに奥で発生する既知のパターン、おそらく取得している最初の>と一致する<の入力をいつでもスキャンできます。

3
a CVn

入力ストリームを出力ストリームにコピーするには、標準的な方法を使用します。

InputStream is=request.getInputStream();
OutputStream os=response.getOutputStream();
byte[] buf = new byte[1000];
for (int nChunk = is.read(buf); nChunk!=-1; nChunk = is.read(buf))
{
    os.write(buf, 0, nChunk);
} 
8
nick