0

我正在尝试将一些 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;
    }
}
4

3 回答 3

1

据我所知,服务器既没有写响应,也没有在run()方法返回之前关闭套接字。所以套接字将坐在那里......客户端将在读取中保持阻塞。

简单的解决方案是关闭服务器的run()方法sock……最好是在一个finally块中,这样它总是会发生。


(以上内容是有效的,即使它不是您当前问题的原因!)

更新

有几件事需要调查。

  1. 您的使用PrintStream是不必要的。您可以(并且应该)直接编组到套接字输出流。这可能会混淆服务器端并导致它阻塞客户端。即使没有, PrintStream 也没有任何用处。

  2. 服务器可能会抛出一些未经检查的异常,导致线程静默退出。这可能会使客户端被阻塞......等待服务器读取或关闭套接字。我之前的建议(至少)会阻止客户端阻塞。但是您还需要安装一个未捕获的异常处理程序来诊断任何未检查的异常和错误。

于 2013-05-18T03:25:25.707 回答
0

对于客户端,编组后,您必须添加sock.shutdownOuput();编组似乎不知道何时结束,因此您必须手动关闭输出流。

于 2013-05-18T05:43:25.373 回答
0

我也有同样的问题。我决定它缓冲在字符串中。

@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();
}
于 2015-05-13T14:10:13.260 回答