JAVA - 使用套接字和线程接收对象不起作用

JAVA - receiving objects using sockets and threads not working

我正在尝试从服务器获取一个对象,但它不起作用。

来自服务器的相关部分(通过调试我看到他确实发送了正确的对象):

    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){ 
        }
    }

来自客户端的相关部分(可能是客户端的错误,当它接收到对象时他跳转到线程的“.start();”行):

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

我试图根据我在此处阅读的答案分成两个线程(服务器和客户端中的一个输入和另一个输出)---但它没有帮助。 还尝试更改输入和输出的顺序 --- 没有成功。

这里有什么问题?

编辑。学生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()); 

    }
}   

尝试使用此 post,使用以下文本和可外部化的搜索部分:很长一段时间以来,我认为缺乏对 JavaFX 属性序列化的支持确实阻止了它们在任何服务器端使用容量。

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

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

JavaFX 属性不可序列化。因此,如果您尝试序列化一个使用 JavaFX 属性作为其状态的对象,您将得到一个异常。

这里有几个选项。一种是不使用 Java 对象序列化,而是使用其他一些序列化技术,例如用 JSON.

表示对象

另一种选择是实施 Externalizable 而不是 SerializableExternalizableSerializable 的子接口,您可以在其中定义自己的数据序列化和反序列化过程。特别是,不是序列化 JavaFX 属性本身,而是序列化它们的内容。

一个简单的例子:

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

请注意,此 class 具有非常简单的结构,因此很容易实现这两个方法。对于更复杂的对象——尤其是那些可能具有循环引用的对象——你需要更加努力地工作。

由于上面定义的class实现了Externalizable,它也实现了Serializable,可以按照通常的方式序列化:

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

阅读我在 JavaFX beans and JPA 上的博客 post 了解更多信息。