SocketとXMLのプログラムにおける問題と解決方法

このQ&Aのポイント
  • SocketとXMLを使用したプログラムにおいて、サーバ側のInputStreamを引数とするXMLパースメソッドがwaitしてしまい、コネクションを終了させる方法を知りたい。
  • クライアント側のOutputStreamを閉じると、クライアントのソケット自体も閉じてしまうため、一度のコネクションで送受信を終了させたい。
  • 現在はBufferedReaderを利用してXML文章を文字列に落としてからStringReaderを使用してXMLパースを行っているが、よりスマートな方法を探している。
回答を見る
  • ベストアンサー

Socket + XML

・クライアントはサーバへXML形式のクエリを送信し、 ・サーバからXML形式のデータを受け取る という単純なプログラムを実装しています。 しかしサーバ側の、InputStreamを引数とするXMLパースメソッドでwaitしてしまって困っています。 かといって、クライアント側のOutputStreamを閉じると、クライアントのソケット自体も閉じてしまいます。 なるべく一度のコネクションで送受信を終了させたいのですが、よい方法はないでしょうか? 一応、BufferedReaderを利用してXML文章を文字列に落としてから StringReaderをbuilder.parseの引数に与えることで解決出来てはいるのですがスマートではない気がしまして。 [Server側]  ServerSocket server_sock = new ServerSocket(12345);  Socket sock = server_sock.accept();  /* XMLパーサビルダ生成 */  DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();  DocumentBuilder builder = fact.newDocumentBuilder();  /* ドキュメント docIn の解析 */  Document docIn = builder.parse(sock.getInputStream());//ここから動かない(clientがoutputを終了するまで待っている?)  (略)  /* 結果ドキュメント docOut の構築*/  Document docOut = builder.newDocument();  (略)  /* docOut 送信 */  TransformerFactory tfactory = TransformerFactory.newInstance();  Transformer transformer = tfactory.newTransformer();  transformer.transform(new DOMSource(docOut), new StreamResult(sock.getOutputStream()));  sock.getInputStream().close();  sock.getOutputStream().close();  sock.close(); [Client側]  Socket sock = new Socket("localhost", 12345);  /* XMLパーサビルダ生成 */  DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();  DocumentBuilder builder = fact.newDocumentBuilder();  /* クエリドキュメント docOut の構築*/  Document docOut = builder.newDocument();  (略)  /* docOut 送信 */  TransformerFactory tfactory = TransformerFactory.newInstance();  Transformer transformer = tfactory.newTransformer();  transformer.transform(new DOMSource(docOut), new StreamResult(sock.getOutputStream()));  sock.getOutputStream().flush();  //sock.getOutputSream().close();//これにすると、socketが閉じてしまう  /* 結果ドキュメント docIn の解析 */  Document docIn = builder.parse(sock.getInputStream());//サーバから結果が送信されないので、クライアントはここで停止  (略)

  • Java
  • 回答数1
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • haraga
  • ベストアンサー率56% (36/64)
回答No.1

そもそもクライアントからの送信は確認できているのですか?

________j_
質問者

お礼

デバッグで確認できています。 ソケットプログラミングに詳しくなかったのですが、ソケットを閉じない限りInputStreamのストリームの終端が見えないのなら、そもそもパーサに直接ソケットのInputStreamを渡すのはよくない気がしてきました。 なんらかのデータ解析を行ってから、文字列をパーサに渡すべきでしょうか。(HTTPプロトコルのように) たとえば送信時にXML文章の終了記号として "\r\n\0\r\n"を付加し、サーバ側のXMLパーサにInputStream()を直接渡さずにBufferedReaderを利用してその"\0"を検知させることで思ったとおりの送受信が行われます。、 [サーバ] BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream())); String str = ""; for(String line; !(line = br.readLine()).equals("\0");)  str += line;  /* XMLパーサビルダ生成 */  DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();  DocumentBuilder builder = fact.newDocumentBuilder();  /* ドキュメント docIn の解析 */  Document docIn = builder.parse(new InputSource(new StringReader(str)));  (略)  /* 結果ドキュメント docOut の構築*/  Document docOut = builder.newDocument();  (略)  /* docOut 送信 */  TransformerFactory tfactory = TransformerFactory.newInstance();  Transformer transformer = tfactory.newTransformer();  transformer.transform(new DOMSource(docOut), new StreamResult(sock.getOutputStream()));  sock.close(); [クライアント] (略) /* docOut 送信 */  TransformerFactory tfactory = TransformerFactory.newInstance();  Transformer transformer = tfactory.newTransformer();  transformer.transform(new DOMSource(docOut), new StreamResult(sock.getOutputStream())); sock.getOutputStream().write("\r\n\0\r\n".getBytes());  sock.getOutputStream().flush();  /* 結果ドキュメント docIn の解析 */  Document docIn = builder.parse(sock.getInputStream());//サーバ側がsocketをclose()するのでInputStream()の終端も見える  (略)

関連するQ&A

  • XMLの処理について

    javaでxmlをsoapで投げる処理をしています。 <クライアント> DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.parse( new File( "test.xml" ) ); Element elm = doc.getDocumentElement(); result = WebService( elm ); <サーバ> public Object WebService( Element elm ) { return 'elmを処理した結果'; } このクライアントの処理をperlで行いたいのですが、可能でしょうか?  : $service = SOAP::Lite->Service( "xxx.wdsl" ); open( XML, "test.xml" ); @xml = <XML>; ?? ここの処理はどうすれば ?? result = $service.WebService( @xml );  :

  • 現在、JAVAのXML/DOMを利用して

    現在、JAVAのXML/DOMを利用して XMLを生成してタグ、インデントを含めそのまま WEBブラウザに出力するようにしたいと思っていますが、 この場合、XMLのタグがWEBブラウザでタグと認識され、除去されてしまいます。 XMLのタグを除去せず、そのまま画面に表示することは可能でしょうか? 可能であれば、その方法を教えていただけませんか? 宜しくお願いします。 今書いているコード DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder; builder = factory.newDocumentBuilder(); DOMImplementation domImpl = builder.getDOMImplementation(); Document document = domImpl.createDocument("","test",null); Element test = document.getDocumentElement(); Element aiueoNode = document.createElement("AAA"); Element abcdeNode = document.createElement("BBB"); aiueoNode.appendChild(document.createTextNode("あいうえお"); abcdeNode.appendChild(document.createTextNode("ABCDE"); test.appendChild(aiueoNode); test.appendChild(abcdeNode); TransformerFactory tf = TransformerFactoryImpl.newInstance(); tf.setAttribute(TransformerFactoryImpl.INDENT_NUMBER, "2"); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); PrintWriter out = new PrintWriter(response.getOutputStream(), true); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); DOMSource source = new DOMSource(document); transformer.transform(source, result); /**XMLを文字列にして出力**/ out.println(writer.toString()); 現在IE出力例は「あいうえおABCDE」ですが、下記のように出力したいです。 「<test>     <AAA>あいうえお</AAA>     <BBB>ABCDE</BBB> </test>」 宜しくお願いします。 java:1.6/tomcat:6.0/IE:8

    • ベストアンサー
    • Java
  • Eclispe上でXML書込み可能が、E以外出来ず

    Eclispe上では、任意の値を、例えば(ex.xml等)に書込み可能なのですが、 ランナブルjarにして、デスクトップ上に他ファイルも含めて置き、jarを起動して、 XMLに書込みしようとしても書込みできません。 XMLは標準で作成してます(windows7 Home edition 管理者権限で動作 JDK1.7.0_05)。 色々調査しましたが原因不明です。 読み込みは問題ありません。XSLTにも関連していないようです。 何が違うのでしょうか? みなさま、よろしくお願いいたします。 ソースは以下の通り、 import java.io.File; import java.io.IOException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; public class XMLBasic { /*-------------------------* * Variables. * *-------------------------*/ /*----- For XML -----*/ /* XSL */ final static String XSL_FILE="resource\\style.xsl"; /**/ static Element element; /*-------------------------* * Methods. * *-------------------------*/ /*----- Rewrite -----*/ public static void rw(String value, String tagName, int itemNum, String xmlFileName, String xslFileName) { Document document=null; try { document=DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(xmlFileName)); } catch (SAXException e) { } catch (IOException e) { } catch (ParserConfigurationException e) {} document.getElementsByTagName(tagName).item(itemNum).getFirstChild().setNodeValue(value); TransformerFactory tfactory=TransformerFactory.newInstance(); Transformer transformer=null; try { transformer=tfactory.newTransformer(new StreamSource(new File(xslFileName))); } catch (TransformerConfigurationException e) {} try { transformer.transform(new DOMSource(document), new StreamResult(new File(xmlFileName))); } catch (TransformerException e) {} } }

    • ベストアンサー
    • Java
  • ByteArrayOutputStreamでの出力について

    以下のソース(抜粋)でこのreturnの箇所で「型の不一致」エラーが出てしまいます。最後にこのクラスのこのメソッドからServletへ値を戻したいのですが。 メソッドのデータ型はbyteですし、Servlet側の受容れる為の変数もbyte型にしています。 経験不足で原因が見つけられません。どなたかご教授をお願い致しますm(__)m Document document = DocumentBuilderFactory.newInstance() .newDocumentBuilder() .getDOMImplementation() .createDocument("", "rt", null); ~文字列からDOMを使ってxmlの生成処理~ Transformer transformer = TransformerFactory.newInstance() .newTransformer(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); transformer.transform(new DOMSource(document),new StreamResult(baos)); byte[] buff = baos.toByteArray(); return buff;

    • ベストアンサー
    • Java
  • JAXPでDOMを保存する際、'&'を'&amp;'に展開したくない

    当方JAXPでXMLを扱っています。 今悩んでいることなのですが、DOMオブジェクトを保存しようとすると、実態参照をつくることができません。 何かよい方法はありませんか? また、実態参照について、私のほうに根本的な間違いや知らなければならないことがあるのでしょうか。 よろしくお願いします。 ----------サンプルソース------------ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = builder.newDocument(); Element root = document.createElement("root"); // 実態参照を挿入 root.appendChild(document.createTextNode("&nbsp;")); document.appendChild(root); // DOMの状態では挿入したものがそのまま参照できる System.out.println("on dom : " + root.getTextContent()); // 保存 Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.transform(new DOMSource(document), new StreamResult(System.out)); --------------結果----------------- on dom : &nbsp; <?xml version="1.0" encoding="UTF-8" standalone="no"?><root>&amp;nbsp;</root> --------------望む結果-------------- on dom : &nbsp; <?xml version="1.0" encoding="UTF-8" standalone="no"?><root>&nbsp;</root> --------------------------------------

    • ベストアンサー
    • Java
  • ストリング文字列をDocumentオブジェクトに格納したい

    文字列として受け取ったxmlをDocumentオブジェクトに格納したいと考えて DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(ファイルパス); とすればファイルを取得してDocumentオブジェクトに入れることはできたのですが、ファイルパスではなくString文字列としてxmlを受け取った場合、どのようにすればDocumentオブジェクトに格納できるのかわかりません。 どのようにすればよろしいのでしょうか?

    • ベストアンサー
    • Java
  • XMLの読み込み

    DocumentBuilderFactory,DocumentBuilder等を使って XMLドキュメントの読み込みを行っています。 例えば、以下の様なXMLドキュメントがあった時 <text>内の読み込みを行うと、テキストテキスト2と なってしまいます。 「テキスト<p/><p/>テキスト2」として取得したいのですが 何かいい方法ないでしょうか? ----------------------------------------- <?xml version="1.0" encoding="Shift_JIS"?> <root> <text> テキスト<p/><p/>テキスト2</text> </root> ----------------------------------------- それとも、XMLドキュメント上、「<p/>」に意味があるのでしょうか? ※プログラム一部抜粋 //-- DOMオブジェクト初期化 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); //-- XMLファイル読み込み this.doc = docBuilder.parse(new File(strPath)); this.doc.getDocumentElement().normalize();

    • ベストアンサー
    • Java
  • Element→Document→InputStream

    お世話になります。 バイト配列 buf をもとに、XMLエレメントを作成しています。 ↓↓↓ DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dbfactory.newDocumentBuilder(); Document document = builder.parse( new ByteArrayInputStream( buf ) ); Element element = document.getDocumentElement(); 上記、element から バイト配列buf に戻すことは可能でしょうか? (イメージ的に、element.getBytes() のような事をしたいです。) よろしくお願い致します。

    • ベストアンサー
    • Java
  • JAXPのDTD検証

    JAXPを使ってXMLの解析をしてるのですが、DTD検証を無効にする方法はあるのでしょうか? XMLに、DTDが記述されているとURLを参照しようとしてエラーになってしまいます。 これを無視するようにしたいのですが。。 ---ソース--- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse( "hoge._xml" );

    • ベストアンサー
    • Java
  • DOMツリーの作り方。

    XMLのDOMツリーをjavaで作りたいです。 ---Root.xmlファイル--- <?xml version="1.0!> <root></root> ------ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dbf.newDocumentBuilder(); Document root = builder.parse("c:/tmp/Root.xml"); /*rootの子ノードとして新しいノード(title)を追加していく*/ といったやり方があると思うんですが、 そうではなく、プログラム内でrootドキュメントを作ってtitle子ノードを追加していきたいんです。 つまり、Root.xmlに頼りたくないということなんですが、どうしたらよいでしょうか?

    • 締切済み
    • XML

専門家に質問してみよう