Java 如何通过套接字 InputStream 发送 XML 数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1428075/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:57:20  来源:igfitidea点击:

How to send XML data through socket InputStream

javaxmlsocketsstream

提问by Davide Aversa

I'm trying to write a client-server application in Java with an XML-based protocol. But I have a great problem!

我正在尝试使用基于 XML 的协议用 Java 编写客户端-服务器应用程序。但是我有一个很大的问题!

See this part of client code:

看这部分客户端代码:

InputStream incoming = skt.getInputStream(); //I get Stream from Socket.
OutputStream out = skt.getOutputStream();

[...]

XMLSerializer serializer = new XMLSerializer();
//This create an XML document.
tosend = WUTPClientWriter.createMessage100(projectid, cpuclock, cpunumber);
serializer.setOutputByteStream(out);
serializer.serialize(tosend);

At this point server fall in deadlock. It wait for EOF but I can't send it because if I use

此时服务器陷入僵局。它等待 EOF 但我无法发送它,因为如果我使用

out.close();

or

或者

skt.shutdownOutput();

I close the Socket and I must keep this connection alive.

我关闭了 Socket,我必须保持这个连接处于活动状态。

I can't send '\0' becouse I get Parse Error in the server.

我无法发送 '\0' 因为我在服务器中收到解析错误。

How can I do it? Can I "close" the output stream without closing the socket?

我该怎么做?我可以在不关闭套接字的情况下“关闭”输出流吗?

RESOLVEDI've created new class XMLStreamOutput and XMLStreamInput with advanced Stream gesture.

议决我创建新类XMLStreamOutput和XMLStreamInput拥有先进的流姿态。

采纳答案by Davide Aversa

I've resolved with this four class:

我已经解决了这四门课:

1)

1)

public class XMLOutputStream extends  ByteArrayOutputStream {

 private DataOutputStream outchannel;

 public XMLOutputStream(OutputStream outchannel) {
     super();
     this.outchannel = new DataOutputStream(outchannel);
 }

 public void send() throws IOException {
     byte[] data = toByteArray();
     outchannel.writeInt(data.length);
     outchannel.write(data);
     reset();
 }
}

2)

2)

public class XMLSender {

 public static void send(Document tosend, OutputStream channel) throws   TransformerConfigurationException, IOException {
     XMLOutputStream out = new XMLOutputStream(channel);

     StreamResult sr = new StreamResult(out);
     DOMSource ds = new DOMSource(tosend);
     Transformer tf = TransformerFactory.newInstance().newTransformer();

     try {
         tf.transform(ds, sr);
     } catch (TransformerException ex) {
         Logger.getLogger(XMLSender.class.getName()).log(Level.SEVERE, null, ex);
     }

     out.send();
 }
}

3)

3)

public class XMLInputStream extends ByteArrayInputStream {

 private DataInputStream inchannel;

 public XMLInputStream(InputStream inchannel) {
     super(new byte[2]); 
     this.inchannel = new DataInputStream(inchannel);
 }

 public void recive() throws IOException {
     int i = inchannel.readInt(); 
     byte[] data = new byte[i];
     inchannel.read(data, 0, i); 
     this.buf = data; 
     this.count = i;
     this.mark = 0;
     this.pos = 0;
 }

}

4)

4)

public class XMLReceiver {

 public static Document receive(InputStream channel) throws ParserConfigurationException, TransformerConfigurationException, IOException, SAXException {

     DocumentBuilderFactory docBuilderFact = DocumentBuilderFactory.newInstance();
     DocumentBuilder docBuilder = docBuilderFact.newDocumentBuilder();
     Document request = null;


     XMLInputStream xmlin = new XMLInputStream(channel);

     xmlin.recive();

     request = docBuilder.parse(xmlin);

     return request;
 }
}

回答by rob

You don't want to close the socket's OutputStream, because the socket only has one OutputStream.

您不想关闭套接字的 OutputStream,因为套接字只有一个 OutputStream。

It looks like you just need to flush your OutputStream after writing to it.

看起来你只需要在写入后刷新你的 OutputStream 。

out.flush();

EDIT: Thanks for the extra info. If you're reading the socket like this, receiver needs to know when you're done writing. An InputStream only knows you're done writing if you close the socket.

编辑:感谢您提供额外信息。如果您像这样读取套接字,接收器需要知道您何时完成写入。InputStream 只有在关闭套接字时才知道您已完成写入。

But since you have already stated you can't close the socket, you need another way of telling the receiving side that you're done. You either need to use a special type of stream which knows about the data being sent, or you need to set up a contract for writing/reading the appropriate amount of data.

但是既然你已经声明你不能关闭套接字,你需要另一种方式告诉接收方你已经完成了。您要么需要使用一种特殊类型的流来了解正在发送的数据,要么需要建立一个契约来写入/读取适当数量的数据。

It would probably be easiest to send the data as an Object (using ObjectOutputStream/ObjectInputStream--maybe you don't even need to convert to XML).

将数据作为对象发送可能是最简单的(使用 ObjectOutputStream/ObjectInputStream——也许您甚至不需要转换为 XML)。

If you don't want the overhead associated with Object streams, the simple solution is to compute the length of the data being sent, and send that number just prior to sending the actual data. In this case, you can use a DataOutputStream/DataInputStream. Send the number of bytes to read, followed by the data. On the receiving side, read the number, then read the given number of bytes into a temporary variable and feed that to DocumentBuilder.parse(InputStream).

如果您不想要与对象流相关的开销,简单的解决方案是计算正在发送的数据的长度,并在发送实际数据之前发送该数字。在这种情况下,您可以使用 DataOutputStream/DataInputStream。发送要读取的字节数,后跟数据。在接收端,读取数字,然后将给定的字节数读入一个临时变量并将其提供给 DocumentBuilder.parse(InputStream)。

On the sending end, you would do this:

在发送端,你会这样做:

DataOutputStream out = new DataOutputStream(s.getOutputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();

XMLSerializer serializer = new XMLSerializer();
serializer.setOutputByteStream(baos);
tosend = WUTPClientWriter.createMessage100(projectid, cpuclock, cpunumber);
serializer.serialize(tosend);

out.writeInt(baos.size());
out.write(baos.toByteArray());

out.flush();

Then on the receiving end, you do something like the following:

然后在接收端,您执行以下操作:

DataInputStream in = new DataInputStream(s.getInputStream());

int len = in.readInt();
byte[] xml = new byte[len];
in.read(xml, 0, len);

Document doc = builder.parse(new ByteArrayInputStream(xml));