Как отправить данные XML через сокет InputStream - PullRequest
1 голос
/ 15 сентября 2009

Я пытаюсь написать клиент-серверное приложение на Java с протоколом на основе XML. Но у меня есть большая проблема!

См. Эту часть кода клиента:

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

В этот момент сервер зашел в тупик. Это ждет EOF, но я не могу отправить его, потому что, если я использую

out.close();

или

skt.shutdownOutput();

Я закрываю сокет и должен поддерживать соединение.

Я не могу отправить '\ 0', потому что я получаю Parse Error на сервере.

Как я могу это сделать? Можно ли «закрыть» выходной поток, не закрывая сокет?

ПОСТАНОВИЛИ Я создал новый класс XMLStreamOutput и XMLStreamInput с расширенным жестом Stream.

Ответы [ 2 ]

4 голосов
/ 14 марта 2010

Я решил с этим четыре класса:

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)

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)

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)

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;
 }
}
1 голос
/ 15 сентября 2009

Вы не хотите закрывать OutputStream сокета, потому что сокет имеет только один OutputStream.

Похоже, вам просто нужно сбросить свой OutputStream после записи в него.

out.flush();

РЕДАКТИРОВАТЬ: Спасибо за дополнительную информацию. Если вы читаете сокет, как это, получатель должен знать, когда вы закончите писать. InputStream знает, что вы закончили писать, только если закрыли сокет.

Но поскольку вы уже заявили, что не можете закрыть сокет, вам нужен другой способ сообщить принимающей стороне, что вы закончили. Либо вам нужно использовать специальный тип потока, который знает о отправляемых данных, либо вам нужно заключить договор на запись / чтение соответствующего объема данных.

Вероятно, было бы проще всего отправить данные в виде объекта (используя ObjectOutputStream / ObjectInputStream - возможно, вам даже не нужно конвертировать в XML).

Если вам не нужны накладные расходы, связанные с потоками объектов, простое решение состоит в том, чтобы вычислить длину отправляемых данных и отправить это число непосредственно перед отправкой фактических данных. В этом случае вы можете использовать DataOutputStream / DataInputStream. Отправьте количество байтов для чтения, а затем данные. На принимающей стороне прочитайте число, затем прочитайте указанное количество байтов во временную переменную и передайте ее в DocumentBuilder.parse (InputStream).

На отправляющей стороне вы должны сделать это:

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();

Затем на приемном конце вы делаете что-то вроде следующего:

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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...