簡體   English   中英

使用JAXB從套接字解組xml后,客戶端被阻止

[英]Client is blocked after unmarshalling xml from socket using JAXB

我正在嘗試將一些xml從客戶端發送到服務器,並讓服務器在接收到數據后將消息發送回客戶端。 如果它只是發送xml,那么它將平穩運行,但是當客戶端期望響應時,它將永遠阻塞。 我從另一篇文章中讀到,解組可關閉套接字,所以我改用了filterStream,但似乎無法解決問題。 有任何想法嗎?

這是我的代碼:

客戶

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.net.Socket;
import javax.xml.bind.annotation.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class Client {

    public static void main(String args[]) throws JAXBException, IOException {
        JAXBContext context = JAXBContext.newInstance(Product.class);
        Socket sock = new Socket("localhost", 4000);
        Marshaller m = context.createMarshaller();
        BufferedReader br = new BufferedReader(new InputStreamReader(new MyInputStream(sock.getInputStream())));
        PrintStream ps = new PrintStream(sock.getOutputStream());
        Product object = new Product();
        object.setCode("WI1");
        object.setName("Widget Number One");
        object.setPrice(BigDecimal.valueOf(300.00));
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.setProperty(Marshaller.JAXB_FRAGMENT, true);

        System.out.println("Data Sent");
        m.marshal(object, ps);

        System.out.println("Waiting for response from server");
        String msg = br.readLine(); // runs smoothly if client doesn't wait for response
        if (msg != null) {
            System.out.println(msg);
        }
        br.close();
        sock.close();
    }
}

@XmlRootElement
class Product {

    private String code;
    private String name;
    private BigDecimal price;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

服務器:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.math.BigDecimal;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;

public class Server {

    public static void main(String a[]) throws IOException, JAXBException {
        Socket sock;
        ServerSocket servsock = new ServerSocket(4000, 1);
        while (true) {
            sock = servsock.accept();
            new WorkerThread(sock).start();
        }
    }
}

class WorkerThread extends Thread {

    Socket sock;
    WorkerThread(Socket s) {
        sock = s;
    }

    public void run() {
        try {
            PrintStream out = new PrintStream(sock.getOutputStream()); // to send ack back to client;
            BufferedReader in = new BufferedReader(new InputStreamReader(new MyInputStream(sock.getInputStream())));;
            JAXBContext context = JAXBContext.newInstance(Product.class);  
            Unmarshaller um = context.createUnmarshaller();
            XMLInputFactory xif = XMLInputFactory.newFactory();
                StreamSource ss = new StreamSource(in);
                XMLStreamReader xsr = xif.createXMLStreamReader(ss);
                xsr.nextTag();

                JAXBElement<Product> xmlToJava = um.unmarshal(xsr, Product.class);

                Product product = xmlToJava.getValue();
                System.out.println("closing");
                xsr.close();

                System.out.println(product.getName());
                System.out.println(product.getCode());
            System.out.println(product.getPrice());
            out.println("data recieved");
            out.flush();
        } catch (IOException ex) {
            Logger.getLogger(WorkerThread.class.getName()).log(Level.SEVERE, null, ex);
        } catch (JAXBException ex) {
            Logger.getLogger(WorkerThread.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XMLStreamException ex) {
            Logger.getLogger(WorkerThread.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

class MyInputStream extends FilterInputStream {

    public MyInputStream(InputStream in) {
        super(in);
    }

    @Override
    public void close() {
    }
}

@XmlRootElement
class Product {

    private String code;
    private String name;
    private BigDecimal price;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

據我所知,服務器既沒有編寫響應,也沒有在run()方法返回之前關閉套接字。 因此,套接字將只坐在那里...,並且客戶端將在讀取中保持阻塞狀態。

一種簡單的解決方案是讓服務器的run()方法關閉sock ...最好在finally塊中使其始終發生。


(即使不是直接引起問題的原因,以上內容也有效!)

更新

有幾件事需要研究。

  1. 您不需要使用PrintStream 您可以(並且應該)直接封送至套接字輸出流。 這可能會混淆服務器端並導致其阻塞客戶端。 即使沒有,PrintStream也沒有任何用處。

  2. 服務器可能拋出一些未經檢查的異常,導致線程靜默退出。 這可能會使客戶端處於阻塞狀態……等待服務器讀取或關閉套接字。 我以前的建議將(至少)防止客戶端阻塞。 但是,您還需要安裝未捕獲的異常處理程序,以診斷任何未經檢查的異常和錯誤。

對於客戶端,在封送處理之后,您必須添加sock.shutdownOuput(); 封送處理似乎不知道何時結束,因此您必須手動關閉輸出流。

我也有同樣的問題。 我決定將其緩沖在字符串中。

@Override
public void run() {
    try {
        while(true) {
            try(
                Socket socket = ss.accept();
                DataInputStream is = new DataInputStream(socket.getInputStream());
                DataOutputStream os = new DataOutputStream(socket.getOutputStream());
            ) {
                socket.setSoTimeout(1000);

                Unmarshaller unmarshaller = JAXBContext.newInstance(Sale.class).createUnmarshaller();
                unmarshaller.setEventHandler(new ValidationEventHandler() {
                    @Override
                    public boolean handleEvent(ValidationEvent event) {
                        if(event.getSeverity() == ValidationEvent.FATAL_ERROR) {
                            InvoiceSrv.logMessage(event.getMessage());
                        }

                        return true;
                    }
                });

                Sale sale = (Sale)unmarshaller.unmarshal(new StringReader(is.readUTF()));
                Response response = getResponse(sale);

                StringWriter writer = new StringWriter();
                Marshaller marshaller = JAXBContext.newInstance(Response.class).createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                marshaller.marshal(response, writer);

                os.writeUTF(writer.toString());
            }
        }
    }
    catch(SocketException e) { e.printStackTrace(); } // for close !!!
    catch(IOException | JAXBException e) {
        InvoiceSrv.logMessage(e);
    }
}

和客戶

public static Response send(Sale sale) throws DeviceException {
    try(
        Socket socket = new Socket(addr, 9999);
        DataInputStream is = new DataInputStream(socket.getInputStream());
        DataOutputStream os = new DataOutputStream(socket.getOutputStream());
    ) {
        StringWriter writer = new StringWriter();
        Marshaller marshaller = JAXBContext.newInstance(Sale.class).createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(sale, writer);

        os.writeUTF(writer.toString());

        Unmarshaller unmarshaller = JAXBContext.newInstance(Response.class).createUnmarshaller();
        Response response = (Response)unmarshaller.unmarshal(new StringReader(is.readUTF()));

        return response;
    }
    catch(IOException | JAXBException e) {
        e.printStackTrace();
    }

    throw new DeviceException();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM