简体   繁体   English

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

[英]How to send XML data through socket InputStream

I'm trying to write a client-server application in Java with an XML-based protocol. 我正在尝试使用基于XML的协议用Java编写客户端服务器应用程序。 But I have a great problem! 但是我有一个大问题!

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. 我关闭了套接字,并且必须保持此连接有效。

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? 我可以在不关闭套接字的情况下“关闭”输出流吗?

RESOLVED I've created new class XMLStreamOutput and XMLStreamInput with advanced Stream gesture. 解决方法我创建了具有高级Stream手势的新类XMLStreamOutput和XMLStreamInput。

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;
 }
}

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. 在这种情况下,您可以使用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). 在接收方,读取该数字,然后将给定的字节数读取到一个临时变量中,并将其提供给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));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM