2009-09-15 6 views
1

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

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

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' becouse Я получаю Parse Error на сервере.

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

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

+1

Как вы можете сделать что? Вы на самом деле не описали, что происходит не так. Вы также не упомянули разбор, кроме как в заголовке ... –

+0

Извините :(Однако проблема в том, что сервер зашел в тупик. Подождите, пока клиентский вход закрывается, но я не могу его закрыть. –

ответ

4

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

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

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

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

out.flush(); 

EDIT: Спасибо за дополнительную информацию. Если вы читаете такой сокет, приемник должен знать, когда вы закончите писать. 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)); 
+0

Не работает. on: request = docBuilder.parse (connection.getInputStream()); –

+0

Я обновил свой ответ сразу после публикации вашего комментария, но вижу, что вы нашли другое решение. :) – rob

Смежные вопросы