- PR -

ソケットからのXML文書のパース

投稿者投稿内容
banboo
大ベテラン
会議室デビュー日: 2003/12/05
投稿数: 210
投稿日時: 2004-08-11 17:20
クライアント―サーバ間でソケットプログラムを行っております。

下記のプログラムにおいて、

処理内容は、クライアント側で、XML文書を読み込んで、文字列に変換しサーバに送信します。

サーバ側で、socketからInputStreamを得て、
InputStream ist = socket.getInputStream();

それをパースするです。それで、パースする所で処理がとまります(エラーは
クライアント側にも、サーバ側にも出力されていない)。

System.out.println("check-point1");

Document doc = builder.parse(ist);<---ここで処理がとまっている模様

System.out.println("check-point2");

質問したい事は、

1. 原因はなにか。

2. どのように問題を解析すればよいのか
特に、今回のように、処理がとまり、エラーが出力されていない場合に
どのように解析すればよいのでしょうか?

どなたかご存知の方がいらっしゃいましたらご教授御願い致します。

-------------------------------------------------------------
import java.net.*;
import java.io.*;

public class HelloWorldSocketClient {



private static final String XMLDOCUMENT =
"C:\\eclipse-SDK-2.1.1-win32\\eclipse\\workspace\\sample\\baseXMLDocument\\ConvertTest1.xml";


// private static final String XMLDOCUMENT = "ConvertTest1.txt";
public static void main(String[] args) {

try {
// ソケットを生成
Socket socket = new Socket("localhost", 5555);

// 出力ストリームを取得
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
// 入力ストリームを取得
BufferedReader in =
new BufferedReader(
new InputStreamReader(socket.getInputStream()));

// XML文書のStringをサーバーに送る



String xmlString = null;

File file = new File(XMLDOCUMENT);

xmlString = makeStringFromFile(file);

// System.out.println(xmlString);

out.println(xmlString);



// out.println("Hello World!");
// 読み込んだデータを表示
System.out.println(in.readLine());

// 入出力ストリームを閉じる
out.close();
in.close();
// ソケットを閉じる
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public static String makeStringFromFile(File file) throws IOException {

Reader in = null;
try {
in = new FileReader(file);
return (makeStringFromReader(in));
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
}
}
}

public static String makeStringFromReader(Reader reader)
throws IOException {

BufferedReader breader = null;
PrintWriter pwriter = null;
StringWriter swriter = null;
String result = null;
if (reader instanceof BufferedReader) {
breader = (BufferedReader) reader;
} else {
breader = new BufferedReader(reader);
}
try {
swriter = new StringWriter();
pwriter = new PrintWriter(swriter);
String line;
while ((line = breader.readLine()) != null) {
pwriter.println(line);
}
pwriter.flush();
result = swriter.toString();
} finally {
if (pwriter != null) {
pwriter.close();
} else if (swriter != null) {
swriter.close();
}
}
return (result);
}

}

-----------------------------------------------

import java.net.*;
import java.io.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class HelloWorldSocketServer {
public static void main(String[] args) {
try {
// サーバーソケットの生成
ServerSocket serverSocket = new ServerSocket(5555);

System.out.println("クライアントからの接続をポート5555で待ちます");
// クライアントからの接続を待ちます
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress() + "から接続を受付ました");

// 出力ストリームを取得
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

InputStream ist = socket.getInputStream();

/*
// 入力ストリームを取得
BufferedReader in =
new BufferedReader(
new InputStreamReader(socket.getInputStream()));
*/

BufferedReader in = new BufferedReader(new InputStreamReader(ist));

DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//名前空間を認識する
factory.setNamespaceAware(true);
//builder object(パーサー) を作る
DocumentBuilder builder = factory.newDocumentBuilder();

System.out.println("check-point1");

Document doc = builder.parse(ist);

System.out.println("check-point2");

// 読み込んだ行をそのまま出力ストリームに書き出す
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println(inputLine);
}

System.out.println("処理が終了したので接続を切ります");

// 入出力ストリームを閉じる
out.close();
in.close();
// ソケットを閉じる
socket.close();
// サーバーソケットを閉じる
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (SAXException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
}

--------------ConvertTest1.xml-------

<?xml version="1.0" encoding="UTF-8"?>
<address>
<item sex="male" custid="E21099">
<name>菅井 学</name>
<access kind="email"></access>
<access kind="url">http://msugai.fc2web.com/java/</access>
<image file="msugai.png" />
</item>
<item sex="male" custid="E27989">
<name>鈴木 竜広</name>
<access kind="email">tsuzuki@hoge.foo.bar</access>
<image file="tsuzuki.png" />
</item>
<item sex="female" custid="E29435">
<name>栃原 宏枝</name>
<access kind="tel">090-xxxx-xxxx</access>
<image file="tochi.png" />
</item>
</address>
SJ0392
ベテラン
会議室デビュー日: 2004/02/05
投稿数: 62
お住まい・勤務地: 神奈川・横浜
投稿日時: 2004-08-11 21:18
サーバ側の read() 待ちじゃないですか?
クライアントにて out.println() 実行後に flush() してないですよね。

この手のフリーズ現象にみえる状況の場合はスレッドダンプしてスタックトレースを確認してみることです。
下記スレッドで解説されているので参照して下さい。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?forum=12&topic=11925
banboo
大ベテラン
会議室デビュー日: 2003/12/05
投稿数: 210
投稿日時: 2004-08-14 22:38
>クライアントにて out.println() 実行後に flush() してないですよね。

flush()を追加してみましたが変化はありませんでした。

スタックトレースは、以下の通りです。

$ java HelloWorldSocketServer
クライアントからの接続をポート5555で待ちます
/127.0.0.1から接続を受付ました
check-point1
check-point2
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at java.net.SocketInputStream.read(SocketInputStream.java:90)
at sun.nio.cs.StreamDecoder$ConverterSD.implRead(StreamDecoder.java:285)

at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:182)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at HelloWorldSocketServer.main(HelloWorldSocketServer.java:64)
----------

サーバ側のコードを少し変更しました。

スタックとレースを見る限り、ストリームからの読みこみがうまくいかない
ようです。

InputStream ist = socket.getInputStream();

BufferedReader in = new BufferedReader(new InputStreamReader(ist));


System.out.println("check-point2");

while ((input = in.readLine()) != null) {


bf.append(input);
}

System.out.println("check-point3");

-----------------

import java.net.*;
import java.io.*;

public class HelloWorldSocketClient {



private static final String XMLDOCUMENT =
"C:\\eclipse-SDK-2.1.2-win32-2\\eclipse\\workspace\\sample\\baseXMLDocument\\ConvertTest1.xml";


// private static final String XMLDOCUMENT = "ConvertTest1.txt";
public static void main(String[] args) {

try {
// ソケットを生成
Socket socket = new Socket("localhost", 5555);

// 出力ストリームを取得
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
// 入力ストリームを取得
BufferedReader in =
new BufferedReader(
new InputStreamReader(socket.getInputStream()));

// XML文書のStringをサーバーに送る

System.out.println("check-point1");

String xmlString = null;

File file = new File(XMLDOCUMENT);

xmlString = makeStringFromFile(file);

// System.out.println(xmlString);

out.println(xmlString);

out.flush();

System.out.println("check-point2");

// out.println("Hello World!");
// 読み込んだデータを表示
System.out.println(in.readLine());

// 入出力ストリームを閉じる
out.close();
in.close();
// ソケットを閉じる
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public static String makeStringFromFile(File file) throws IOException {

Reader in = null;
try {
in = new FileReader(file);
return (makeStringFromReader(in));
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
}
}
}

public static String makeStringFromReader(Reader reader)
throws IOException {

BufferedReader breader = null;
PrintWriter pwriter = null;
StringWriter swriter = null;
String result = null;
if (reader instanceof BufferedReader) {
breader = (BufferedReader) reader;
} else {
breader = new BufferedReader(reader);
}
try {
swriter = new StringWriter();
pwriter = new PrintWriter(swriter);
String line;
while ((line = breader.readLine()) != null) {
pwriter.println(line);
}
pwriter.flush();
result = swriter.toString();
} finally {
if (pwriter != null) {
pwriter.close();
} else if (swriter != null) {
swriter.close();
}
}
return (result);
}

}
----------------

import java.net.*;
import java.io.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class HelloWorldSocketServer {
public static void main(String[] args) {
try {
// サーバーソケットの生成
ServerSocket serverSocket = new ServerSocket(5555);

System.out.println("クライアントからの接続をポート5555で待ちます");
// クライアントからの接続を待ちます
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress() + "から接続を受付ました");

// 出力ストリームを取得
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

InputStream ist = socket.getInputStream();

/*
// 入力ストリームを取得
BufferedReader in =
new BufferedReader(
new InputStreamReader(socket.getInputStream()));
*/

BufferedReader in = new BufferedReader(new InputStreamReader(ist));

DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//名前空間を認識する
factory.setNamespaceAware(true);
//builder object(パーサー) を作る
DocumentBuilder builder = factory.newDocumentBuilder();

System.out.println("check-point1");

String input;

StringBuffer bf = new StringBuffer();

System.out.println("check-point2");

while ((input = in.readLine()) != null) {


bf.append(input);
}

System.out.println("check-point3");

String st = bf.toString();

// Document doc = builder.parse(ist);

Document doc = builder.parse(st);


System.out.println("check-point4");

// 読み込んだ行をそのまま出力ストリームに書き出す
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println(inputLine);
}

out.flush();

System.out.println("処理が終了したので接続を切ります");

// 入出力ストリームを閉じる
out.close();
in.close();
// ソケットを閉じる
socket.close();
// サーバーソケットを閉じる
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (SAXException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
}
ちょま吉
大ベテラン
会議室デビュー日: 2004/08/04
投稿数: 112
投稿日時: 2004-08-15 00:02
一番最初のソースについて。

Document doc = builder.parse(ist);
このparseメソッドはistのどこまで読み込むのかわかりませんが、もし、istのストリームの最後まで読み込むのであれば、クライアント側でなんらかのかたちでストリームの終了をしなくてはならないのではないでしょうか?

この状態は、
1.クライアントからxmlStringを送信する。
2.サーバはそれを受け取るが、ストリームが終わってないので引き続き受信待ちになる。(builder.parse(ist)メソッド内)
3.クライアントは、サーバからのレスポンスの受信待ちになる。
ということで、双方とも受信待ちになっているのだと思います。

間違ってたらすみません。

[ メッセージ編集済み 編集者: sou 編集日時 2004-08-15 00:11 ]

[ メッセージ編集済み 編集者: sou 編集日時 2004-08-15 00:12 ]
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2004-08-16 08:27
banbooさん、こんにちは。

先ず最初に、サーバ側の処理ですが、
builder.parse(ist)した後で readLine()しても
なにも入ってこないでしょう。もうそのストリームは読み終わって
ますから。

本来ここでは、データ処理の結果等を返したいのではないで
しょうか?

つぎに、builder.parse(ist)は istが EOFにならないと終了
しないようですね。(少し自信ありませんが)
クライアント側の出力ストリームを close()または
socket.shutdownOutput()すればサーバ側のパースが終了
するのですが、そうすると今度はクライアントの入力ストリームが
読めなくなり、サーバからの応答が受信できなくなるみたいです。

で、私はこの DOMを使う課題はギブアップしました。

もし、DOMではなくて、SAXを使っても良いのなら、
クライアントから EOF状態を作らなくても、</address>
を検出した時点で、データ処理できるようになりますから、
クライアント、サーバともうまく行くようになるでしょう。

それに、DOMは SAXに比べてパースは楽ですが、その後の
データアクセスは結構大変ですよ。
汎用のライブラリでも作るので無ければ、SAX使って、
専用のクラス(この例ではAddressクラスでしょうか)のオ
ブジェクトを生成したほうが、スッキリして楽だと思います
がどうでしょうか。

(それに、1回の接続で、連続的に処理できるようにもなる
オマケも付きます。)
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-08-16 13:31
XMLテキスト全体を一旦String型でオンメモリにおいて、
StringReaderでくるんでDOMパーサに渡せばよいのではないでしょうか?
banboo
大ベテラン
会議室デビュー日: 2003/12/05
投稿数: 210
投稿日時: 2004-08-16 20:27
>XMLテキスト全体を一旦String型でオンメモリにおいて、
>StringReaderでくるんでDOMパーサに渡せばよいのではないでしょうか?

アドバイスを頂き有り難う御座います。

自分なりに解釈して、なおしてみました。

下記において、

while(input = in.readLine()) != null

にならないので、ループから抜け出せない様です。

InputStream ist = socket.getInputStream();

BufferedReader in = new BufferedReader(new InputStreamReader(ist));
.....
.....

String input;

StringBuffer bf = new StringBuffer();

System.out.println("check-point2");

while ((input = in.readLine()) != null) {


bf.append(input);

System.out.println("inside-loop");
}

System.out.println("check-point3");

String st = bf.toString();

Document doc = builder.parse(new InputSource(new StringReader(st)));

----------------------------

import java.net.*;
import java.io.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class HelloWorldSocketServer_2 {
public static void main(String[] args) {
try {
// サーバーソケットの生成
ServerSocket serverSocket = new ServerSocket(5555);

System.out.println("クライアントからの接続をポート5555で待ちます");
// クライアントからの接続を待ちます
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress() + "から接続を受付ました");

// 出力ストリームを取得
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

InputStream ist = socket.getInputStream();

BufferedReader in = new BufferedReader(new InputStreamReader(ist));

DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//名前空間を認識する
factory.setNamespaceAware(true);
//builder object(パーサー) を作る
DocumentBuilder builder = factory.newDocumentBuilder();

System.out.println("check-point1");

String input;

StringBuffer bf = new StringBuffer();

System.out.println("check-point2");

while ((input = in.readLine()) != null) {


bf.append(input);

System.out.println("inside-loop");
}

System.out.println("check-point3");

String st = bf.toString();

Document doc = builder.parse(new InputSource(new StringReader(st)));


System.out.println("check-point4");

// 読み込んだ行をそのまま出力ストリームに書き出す
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println(inputLine);
}

out.flush();

System.out.println("処理が終了したので接続を切ります");

// 入出力ストリームを閉じる
out.close();
in.close();
// ソケットを閉じる
socket.close();
// サーバーソケットを閉じる
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (SAXException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
}
banboo
大ベテラン
会議室デビュー日: 2003/12/05
投稿数: 210
投稿日時: 2004-08-16 21:46
アドバイスを頂き有り難う御座います。

>つぎに、builder.parse(ist)は istが EOFにならないと終了
>しないようですね。(少し自信ありませんが)

確かに、そのようです。builder.parse(ist)
で処理がとまっております。


>もし、DOMではなくて、SAXを使っても良いのなら、
>クライアントから EOF状態を作らなくても、</address>
>を検出した時点で、データ処理できるようになりますから、
>クライアント、サーバともうまく行くようになるでしょう。

SAXに変更してみました。しかし、それでも

parser.parse(ist, handler);

の部分で処理がとまっております。istが EOFにならなくても
処理を抜けられるようにするにはどのようにすれば
よろしいでしょうか?

どなたかご存知の方がいらっしゃいましたら
ご教授頂けないでしょうか?

import java.net.*;
import java.io.*;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class HelloWorldSocketServer_3 {
public static void main(String[] args) {
try {
// サーバーソケットの生成
ServerSocket serverSocket = new ServerSocket(5555);

System.out.println("クライアントからの接続をポート5555で待ちます");
// クライアントからの接続を待ちます
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress() + "から接続を受付ました");

// 出力ストリームを取得
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

InputStream ist = socket.getInputStream();

//SAXパーサのファクトリーの生成
SAXParserFactory factory = SAXParserFactory.newInstance();

/*
// フィーチャーの設定
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setFeature(
"http://apache.org/xml/features/validation/schema",
true);
*/
// SAXパーサの生成
SAXParser parser = factory.newSAXParser();
// ハンドラの生成
DefaultHandler handler = new MySAXHandler();

System.out.println("check-point1");

parser.parse(ist, handler);//<--ここで処理がとまる

System.out.println("check-point2");

BufferedReader in = new BufferedReader(new InputStreamReader(ist));

System.out.println("check-point3");

out.println("return!");

System.out.println("check-point4");

out.flush();

System.out.println("処理が終了したので接続を切ります");

// 入出力ストリームを閉じる
out.close();
//in.close();
// ソケットを閉じる
socket.close();
// サーバーソケットを閉じる
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (SAXException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
}

--------------

class MySAXHandler extends DefaultHandler {
// ContentHandlerの実装
public void startDocument() throws SAXException {
// System.out.println("startDocument()");
}
public void endDocument() throws SAXException {
System.out.println("endDocument()");
}
public void startElement(java.lang.String uri,
java.lang.String localName,
java.lang.String qName,
Attributes atts)
throws SAXException {

/*
System.out.println("startElement()");
System.out.println("\tnamespace=" + uri);
System.out.println("\tlocal name=" + localName);
System.out.println("\tqualified name=" + qName);
*/

for (int i = 0; i < atts.getLength(); i++) {
/*
System.out.println("\tattribute name=" + atts.getLocalName(i));
System.out.println("\tattribute qualified name=" + atts.getQName(i));
System.out.println("\tattribute value=" + atts.getValue(i));
*/
}
}
public void endElement(java.lang.String uri,
java.lang.String localName,
java.lang.String qName)
throws SAXException {
// System.out.println("endElement()");
}
public void characters(char[] ch,
int start,
int length)
throws SAXException {
// System.out.println("characters()" + new String(ch, start, length));
}
// ErrorHandlerの実装
public void warning(SAXParseException e) {
System.out.println("警告: " + e.getLineNumber() +"行目");
System.out.println(e.getMessage());
}
public void error(SAXParseException e) {
System.out.println("エラー: " + e.getLineNumber() +"行目");
System.out.println(e.getMessage());
}
public void fatalError(SAXParseException e) {
System.out.println("深刻なエラー: " + e.getLineNumber() +"行目");
System.out.println(e.getMessage());
}
}

スキルアップ/キャリアアップ(JOB@IT)