2011-10-03 3 views
9

소켓을 통해 색소폰을 사용하여 xml을 구문 분석하려고 할 때 이상한 현상이 나타났습니다. 분석에서 DataOutputStream이 데이터 앞에 2 바이트를 추가하는 것으로 나타났습니다. 변압기를 사용하여DataOutputStream.writeUTF()가 처음에 2 바이트를 추가하는 이유는 무엇입니까?

0020 50 18 00 20 0f df 00 00 00 9d 3c 3f 78 6d 6c 20 P.. .... ..<?xml 
0030 76 65 72 73 69 6f 6e 3d 22 31 2e 30 22 3f 3e 3c version= "1.0"?>< 
0040 63 6f 6d 70 61 6e 79 3e 3c 73 74 61 66 66 3e 3c company> <staff>< 
0050 66 69 72 73 74 6e 61 6d 65 3e 79 6f 6e 67 3c 2f firstnam e>yong</ 
0060 66 69 72 73 74 6e 61 6d 65 3e 3c 6c 61 73 74 6e firstnam e><lastn 
0070 61 6d 65 3e 6d 6f 6f 6b 20 6b 69 6d 3c 2f 6c 61 ame>mook kim</la 
0080 73 74 6e 61 6d 65 3e 3c 6e 69 63 6b 6e 61 6d 65 stname>< nickname 
0090 3e c2 a7 3c 2f 6e 69 63 6b 6e 61 6d 65 3e 3c 73 >..</nic kname><s 
00a0 61 6c 61 72 79 3e 31 30 30 30 30 30 3c 2f 73 61 alary>10 0000</sa 
00b0 6c 61 72 79 3e 3c 2f 73 74 61 66 66 3e 3c 2f 63 lary></s taff></c 
00c0 6f 6d 70 61 6e 79 3e        ompany> 

메시지 보내기 : DataOutputStream에 의해 보내

메시지

0020 50 18 00 20 b6 b1 00 00 3c 3f 78 6d 6c 20 76 65 P.. .... <?xml ve 
0030 72 73 69 6f 6e 3d 22 31 2e 30 22 20 65 6e 63 6f rsion="1 .0" enco 
0040 64 69 6e 67 3d 22 75 74 66 2d 38 22 3f 3e 3c 63 ding="ut f-8"?><c 
0050 6f 6d 70 61 6e 79 3e 3c 73 74 61 66 66 3e 3c 66 ompany>< staff><f 
0060 69 72 73 74 6e 61 6d 65 3e 79 6f 6e 67 3c 2f 66 irstname >yong</f 
0070 69 72 73 74 6e 61 6d 65 3e 3c 6c 61 73 74 6e 61 irstname ><lastna 
0080 6d 65 3e 6d 6f 6f 6b 20 6b 69 6d 3c 2f 6c 61 73 me>mook kim</las 
0090 74 6e 61 6d 65 3e 3c 6e 69 63 6b 6e 61 6d 65 3e tname><n ickname> 
00a0 c2 a7 3c 2f 6e 69 63 6b 6e 61 6d 65 3e 3c 73 61 ..</nick name><sa 
00b0 6c 61 72 79 3e 31 30 30 30 30 30 3c 2f 73 61 6c lary>100 000</sal 
00c0 61 72 79 3e 3c 2f 73 74 61 66 66 3e 3c 2f 63 6f ary></st aff></co 
00d0 6d 70 61 6e 79 3e         mpany> 

하나 DataOutputStream 정렬을 알 수 있습니다으로 메시지 앞에 2 바이트를 추가합니다. 따라서 색소폰 파서는 예외 "org.xml.sax.SAXParseException : 프롤로그에서 내용을 허용하지 않습니다."를 발생시킵니다. 그러나이 2 바이트를 건너 뛸 때 색소폰 파서는 정상적으로 작동합니다. Additional 나는 DataInputStream이 Transformer 메시지를 읽을 수 없다는 것을 알아 차렸다.

내 질문은 : 왜 DataOutputStream이이 바이트를 추가하고 왜 트랜스포머가 아닌가?

서버 사용의 DataInputStream :

String data = "<?xml version=\"1.0\"?><company><staff><firstname>yong</firstname><lastname>mook kim</lastname><nickname>§</nickname><salary>100000</salary></staff></company>"; 
ServerSocket server = new ServerSocket(60000); 
Socket socket = server.accept(); 
DataOutputStream os = new DataOutputStream(socket.getOutputStream()); 
os.writeUTF(data); 
os.close(); 
socket.close(); 

서버 사용 변압기 :

ServerSocket server = new ServerSocket(60000); 
Socket socket = server.accept(); 
Document doc = createDocument(); 
printXML(doc, os); 
os.close(); 
socket.close(); 

public synchronized static void printXML(Document document, OutputStream stream) throws TransformerException 
{ 
    DOMSource domSource = new DOMSource(document); 
    StreamResult streamResult = new StreamResult(stream); 
    TransformerFactory tf = TransformerFactory.newInstance(); 
    Transformer serializer = tf.newTransformer(); 
    serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8"); 
    serializer.setOutputProperty(OutputKeys.INDENT, "no"); 
    serializer.transform(domSource, streamResult); 
} 

private static Document createDocument() throws ParserConfigurationException 
{ 
    Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 
    Element company = document.createElement("company"); 
    Element staff = document.createElement("staff"); 
    Element firstname = document.createElement("firstname"); 
    Element lastname = document.createElement("lastname"); 
    Element nickname = document.createElement("nickname"); 
    Element salary = document.createElement("salary"); 
    Text firstnameText = document.createTextNode("yong"); 
    Text lastnameText = document.createTextNode("mook kim"); 
    Text nicknameText = document.createTextNode("§"); 
    Text salaryText = document.createTextNode("100000"); 
    document.appendChild(company); 
    company.appendChild(staff); 
    staff.appendChild(firstname); 
    staff.appendChild(lastname); 
    staff.appendChild(nickname); 
    staff.appendChild(salary); 
    firstname.appendChild(firstnameText); 
    lastname.appendChild(lastnameText); 
    nickname.appendChild(nicknameText); 
    salary.appendChild(salaryText); 
    return document; 
} 
여기에 문제를 복제에 관심이있는 사람들을 위해


몇 가지 코드의 DataInputStream을 사용

SAXParserFactory factory = SAXParserFactory.newInstance(); 
SAXParser saxParser = factory.newSAXParser(); 
DefaultHandler handler = new MyHandler(); 
Socket socket = new Socket("localhost", 60000); 
InputSource is = new InputSource(new InputStreamReader(socket.getInputStream())); 
is.setEncoding("UTF-8"); 
//socket.getInputStream().skip(2); // skip over the 2 bytes from the DataInputStream 
saxParser.parse(is, handler); 

클라이언트 : SAX 파서를 사용



클라이언트

Socket socket = new Socket("localhost", 60000); 
DataInputStream os = new DataInputStream(socket.getInputStream()); 
while(true) { 
    String data = os.readUTF(); 
    System.out.println("Data: " + data); 
} 
+0

사용하지만, 첫 번째 XML 텍스트는 '인코딩 = "UTF-8"'을 가지고 있지 않습니다. –

+0

또한 DataInputStream을 왜 사용 하시겠습니까? XML을 읽을 때 필요하지 않습니다. – StaxMan

+0

DataInputStream은 자체 프로토콜을 사용한다는 사실을 모르기 때문에 테스트에 사용되었습니다. –

답변

21

DataOutputStream.writeUTF()의 출력 DataInputStream.readUTF() 의해 판독 될 의도 지정 형식이다. writeUTF 방법

JavaDoc을는 말할 호출 :

는 시스템에 의존하지 않는 수정 UTF-8 인코딩을 사용하여 기본 출력 스트림에 기입.

먼저 출력 스트림에 두 바이트가 기록됩니다 (writeShort 메서드에 따라).이 값은 문자열의 길이가 아니라 실제로 쓰여진 바이트 수입니다. 길이 다음에 문자열의 각 문자가 수정 된 UTF-8 인코딩을 사용하여 차례로 출력됩니다. 예외가 발생하지 않으면 카운터 written이 출력 스트림에 기록 된 총 바이트 수만큼 증가합니다. 이것은 적어도 2 플러스 길이가 str이고, 2를 더한 길이의 3 배에 str이 될 것입니다.

+1

그런 다음 질문에 길이가 2 바이트 만 사용되는 이유가 있습니다. 일반적인 사용 사례는 아니지만 이는 매우 임의적 인 한계처럼 보입니다. – MauganRa

13

데이터를 읽고 쓸 때 항상 동일한 유형의 스트림을 사용하십시오.스트림을 색소 파서에 직접 공급하는 경우는, DataOutputStream를 사용하지 말아주세요.

은 그냥 차이가 있는지 모르겠어요

BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); 
bos.write(os.getBytes("UTF-8")); 
관련 문제