JAVA - receiving objects using sockets and threads

2019-07-23 17:05发布

问题:

I'm trying to get an object from the server, but it does not work.

Relevant section from the server (By Debug I see that he is really sending the correct object):

    public static void main(String[] args){ 
    launch(args);
}

public void start(Stage primaryStage) {

    BorderPane mainPane = new BorderPane();
    mainPane.setStyle("-fx-border-color: black;");
    mainPane.setPadding(new Insets(5,5,5,5));

    GridPane gridPane = new GridPane();
    gridPane.setPadding(new Insets(5,5,5,5));
    gridPane.add(lblStatus,0,1);
    gridPane.add(lblDate,0,2);  

    mainPane.setTop(gridPane);
    createTableView();
    mainPane.setCenter(tableView);

    Scene scene = new Scene(mainPane, 700, 250);
    primaryStage.setTitle("Server"); // Set the window title
    primaryStage.setScene(scene); // Place the scene in the window
    primaryStage.show(); // Display the window
    primaryStage.setAlwaysOnTop(true); 
    primaryStage.setOnCloseRequest(
            new EventHandler<WindowEvent>(){
                public void handle(WindowEvent event) {
                    try { 
                        Platform.exit();
                        System.exit(0);
                        serverSocket.close();
                        socket.close();
                    } 
                    catch(SocketException ex){
                        try {
                            socket.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } 
                    }
                    catch (IOException e) {
                        // TODO Auto-generated catch block
                        Platform.exit();
                        System.exit(0);
                    }
                }
            });

    connectToDB();
    connectionDate=new Date();
    Platform.runLater(() ->lblDate.setText(("Server started at \t"+connectionDate)));
    Platform.runLater(() ->lblStatus.setText(connectionStatus));
    new Thread( () ->
    { 
        try{ 
            // Create a server socket
            serverSocket = new ServerSocket(8000);
            while (true){
                // Listen for a connection request
                socket = serverSocket.accept();

                this.clientNo++;
                clientRequest clientDetails = new clientRequest(clientNo, new Date(), "New Clinet");
                addRowToServerTable(clientDetails);

                new Thread(new HandleAClient(socket)).start();


            }

        }
        catch(SocketException ex){
        }
        catch(IOException ex){ 
        }

    }).start(); 
}

/** Connect to DB */
private void connectToDB(){ 

    // Connection to the database
    try{
        Class.forName(driver);                                                  // Load the JDBC driver
        System.out.println("Driver Loaded");
        connection = DriverManager.getConnection(url, username, password);      // Establish a connection
        System.out.println("Connected to " + url);
        connectionStatus = "Connected to \t" + url;
    }
    catch (java.lang.Exception ex){
        ex.printStackTrace();
        connectionStatus = ex.toString();
    }
}


// Define the thread class for handling new connection
class HandleAClient implements Runnable{

    private Socket socket; // A connected socket

    /** Construct a thread */
    public HandleAClient(Socket socket){
        this.socket = socket;
    }

    /** Run a thread */
    public void run(){
        try{
            // Create data input and output streams
            ObjectOutputStream outputToClient = new ObjectOutputStream(
                    socket.getOutputStream());
            DataInputStream inputFromClient = new DataInputStream(
                    socket.getInputStream());

            // Continuously serve the client
            while (true){
                // Receive sql from the client
                String sql = inputFromClient.readUTF();

                clientRequest clientDetails = new clientRequest(clientNo, new Date(),"New Query");
                addRowToServerTable(clientDetails);

                // Execute SQL
                Object[] rows = executeSQL(sql);
                outputToClient.writeObject(rows);

            }
        }
        catch(SocketException ex){
            try{
                serverSocket.close();
                //socket.close();
            } 
            catch (IOException e){ 
            }
        }
        catch(IOException ex){ 
        }
    }

Relevant section from the client (Probably the mistake on the client, when it receives the object he jumps line ".start ();" Of the Thread.):

    private void connectToServer(){
    try{
        // Create a socket to connect to the server
        socket = new Socket(host, 8000);
        // Create an input stream to receive Object from the server
        fromServer = new ObjectInputStream(socket.getInputStream());
        // Create an output stream to send data to the server
        toServer = new DataOutputStream(socket.getOutputStream());

    }
    catch (Exception ex){
        ex.printStackTrace();
    }
}

private void sendAndGetFromServer(String sqlQuery){
    new Thread(() ->{
        try{

            System.out.println("a1");
            // Send sql query to server
            toServer.writeUTF(sqlQuery);
            //toServer.flush();
            // Get notification from the server

            Student[] rows = (Student[])fromServer.readObject();
            setRowsInTable(rows);
        }
        catch(SocketException ex){
            try{
                socket.close();
            } 
            catch (IOException e){ 
            }
        } 
        catch (Exception ex){
        }
    }).start();

I tried to separate into two Thread (One Input and other Output in Server and client) according to the answers I read here --- but it didn't help. Also tried to change the order of Input and Output --- without success.

  • No errors!
  • The client don't get the object.

What's the problem here?

Edit. Student class:

public class Student implements  Externalizable
{ 
    private final SimpleIntegerProperty ID;
    private final SimpleStringProperty firstName;
    private final SimpleStringProperty lastName;
    private final SimpleStringProperty address;
    private final SimpleObjectProperty<Date> birthDate;
    private final SimpleStringProperty department;
    private final SimpleIntegerProperty pointsAmount;
    private final SimpleObjectProperty<Date> startStudyingDate;
    private final SimpleIntegerProperty failedAmount;
    private final SimpleDoubleProperty average;
    private final SimpleIntegerProperty lavelByGrade;
    private final SimpleStringProperty pic;

    public Student(int ID, String firstName, String lastName, String address,
            Date  birthDate, String department,
            int pointsAmount, Date startStudyingDate, int failedAmount, 
            double average, int  lavelByGrade, String pic){

        this.ID= new SimpleIntegerProperty(ID);
        this.firstName= new SimpleStringProperty(firstName);
        this.lastName= new SimpleStringProperty(lastName);
        this.address= new SimpleStringProperty(address);
        this.birthDate= new SimpleObjectProperty<Date>(birthDate);
        this.department= new SimpleStringProperty(department);
        this.pointsAmount= new SimpleIntegerProperty(pointsAmount);
        this.startStudyingDate= new  SimpleObjectProperty<Date>(startStudyingDate);
        this.failedAmount= new SimpleIntegerProperty(failedAmount);
        this.average= new SimpleDoubleProperty(average);
        this.lavelByGrade= new SimpleIntegerProperty(lavelByGrade);
        this.pic = new SimpleStringProperty(pic);
    }

    public int getID() {
        return ID.get();
    }
    public void setID(int ID) {
        this.ID.set(ID);
    }

    public String getFirstName() {
        return firstName.get();
    }

    public void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }

    public String getLastName() {
        return lastName.get();
    }

    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }

    public String getAddress() {
        return address.get();
    }

    public void setAddress(String address) {
        this.address.set(address);
    }

    public Date getBirthDate() {
        return birthDate.get();
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate.set(birthDate);
    }

    public String getDepartment() {
        return department.get();
    }

    public void setDepartment(String department) {
        this.department.set(department);
    }

    public int getPointsAmount() {
        return pointsAmount.get();
    }

    public void setPointsAmount(int pointsAmount) {
        this.pointsAmount.set(pointsAmount);
    }

    public Date getStartStudyingDate() {
        return startStudyingDate.get();
    }

    public void setStartStudyingDate(Date startStudyingDate) {
        this.startStudyingDate.set(startStudyingDate);
    }

    public int getFailedAmount() {
        return failedAmount.get();
    }

    public void setFailedAmount(int failedAmount) {
        this.failedAmount.set(failedAmount);
    }

    public double getAverage() {
        return average.get();
    }

    public void setAverage(Double average) {
        this.average.set(average);
    }

    public int getLavelByGrade() {
        return lavelByGrade.get();
    }

    public void setLavelByGrade(int lavelByGrade) {
        this.lavelByGrade.set(lavelByGrade);
    }

    public String getPic() {
        return pic.get();
    }

    public void setPic(String pic) {
        this.pic.set(pic);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {

        setID(in.readInt());
        setFirstName((String)in.readObject());
        setLastName((String)in.readObject());
        setAddress((String)in.readObject());
        setBirthDate((Date)in.readObject());
        setDepartment((String)in.readObject());
        setPointsAmount(in.readInt());
        setStartStudyingDate((Date)in.readObject());
        setFailedAmount(in.readInt());
        setAverage(in.readDouble());
        setLavelByGrade(in.readInt());
        setPic((String)in.readObject());
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {

        out.writeInt(getID());
        out.writeObject(getFirstName()); 
        out.writeObject(getLastName()); 
        out.writeObject(getAddress()); 
        out.writeObject(getBirthDate());
        out.writeObject(getDepartment());
        out.writeInt(getPointsAmount()); 
        out.writeObject(getStartStudyingDate()); 
        out.writeInt(getFailedAmount()); 
        out.writeDouble(getAverage()); 
        out.writeInt(getLavelByGrade());
        out.writeObject(getPic()); 

    }
}   

回答1:

JavaFX properties are not Serializable. So if you try to serialize an object that uses JavaFX properties for its state, you will get an exception.

You have a couple of options here. One is simply to not use Java object serialization, but some other serialization technique, such as representing the object with JSON.

The other option is to implement Externalizable instead of Serializable. Externalizable is a subinterface of Serializable in which you define your own process for serializing and deserializing the data. In particular, instead of serializing the JavaFX properties themselves, just serialize their contents.

A simple example:

import java.io.Externalizable ;
import java.io.IOException ;
import java.io.ObjectInput ;
import java.io.ObjectOutput ;

import javafx.beans.property.IntegerProperty ;
import javafx.beans.property.SimpleIntegerProperty ;
import javafx.beans.property.SimpleStringProperty ;
import javafx.beans.property.StringProperty ;

public class Person implements Externalizable {

    private final StringProperty name = new SimpleStringProperty();
    private final IntegerProperty id = new SimpleIntegerProperty();

    public StringProperty nameProperty() {
        return name ;
    }
    public final String getName() {
        return nameProperty().get();
    }
    public final void setName(String name) {
        nameProperty().set(name);
    }

    public IntegerProperty idProperty() {
        return id ;
    }
    public final int getId() {
        return idProperty().get();
    }
    public final void setId(int id) {
        idProperty().set(id);
    }

    // important: must have a no-arg constructor:
    public Person() { }

    public Person(int id, String name) {
        setId(id);
        setName(name);
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        // write id then name
        // note we write the contents of the properties, not the properties 
        // themselves, as the properties are not serializable:
        out.writeInt(getId());
        out.writeObject(getName());
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        // read data back in same order:
        setId(in.readInt());
        setName((String)in.readObject());
    }
}

Note that this class has a pretty simple structure, so it's easy to implement these two methods. For more complex objects - particularly those which may potentially have circular references - you need to work a bit harder.

Since the class defined above implements Externalizable, it also implements Serializable, and can be serialized in the usual way:

ObjectOutputStream oos = ... ;
oos.writeObject(new Person(007, "James Bond"));

Read my blog post on JavaFX beans and JPA for more.



回答2:

Try with this post, search part with following text and Externalizable: For quite a long time, I thought the lack of support for Serialization from JavaFX properties really prevented them from being used in any server-side capacity.

http://www.marshall.edu/genomicjava/2014/05/09/one-bean-to-bind-them-all/

https://gist.github.com/james-d/e485ac525c71e20bb453