-1

I'm developing a Javafx application and I need that clients run only when so server does first. I'm a newbie to socket and concurrent programming and I tried to send from server a string called "Done" when is closed. However, I don't know how to catch the string properly in order to throw the right exception for the closure of the server when the clients are running, because otherwise the clients in execution run even without the server after is stopped and I want to prevent it. Thanks for your help!

That's my client (InitApplication.java)

package com.sailingclub.ui.sailingclub;

import body.entities.Admin;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;

import static java.lang.System.exit;


/**
 * Entry point
 */
public class InitApplication extends Application {


    DataOutputStream toServer = null;
    DataInputStream fromServer = null;

    Parent root = null;
    FXMLLoader loader;


    @Override
    public void start(Stage primaryStage) throws IOException, InterruptedException {


        try {

            // Create a socket to connect to the server
            Socket socket = new Socket("localhost", 8000);

            fromServer = new DataInputStream(socket.getInputStream());
            // Create an output stream to send data to the server
            toServer = new DataOutputStream(socket.getOutputStream());

            primaryStage.setOnCloseRequest(event -> {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // Save file
            });

            loader = new FXMLLoader(new File("src/main/java/com/sailingclub/ui/sailingclub/first/FirstPage.fxml").toURI().toURL());
            root=loader.load();

            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.show();

        } catch (Exception e) {
            if (e instanceof ConnectException) {
                loader = new FXMLLoader(new File("src/main/java/com/sailingclub/ui/sailingclub/error.fxml").toURI().toURL());
                root = loader.load();
                Scene scene = new Scene(root);
                primaryStage.setScene(scene);
                primaryStage.show();

            }
            else {
                e.printStackTrace();
            }
        }
    }


    public static void main(String[] args) {

        var beginning=new Admin();

        beginning.notifyGenerator("Membership");
        beginning.notifyGenerator("Storage");

        launch();
    }
}

and that's my server (Server.java)

package body.core.ClientServer;

import com.sailingclub.ui.sailingclub.InitApplication;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;


/**
 * Server side for Client-Server connection
 */
public class Server extends Application {

    @Override
    public void start(Stage stage) throws Exception {

        TextArea ta = new TextArea();
        // Create a scene and place it in the stage
        Scene scene = new Scene(new ScrollPane(ta), 450, 200);
        stage.setTitle("Server"); // Set the stage title
        stage.setScene(scene); // Place the scene in the stage
        stage.show(); // Display the stage





        new Thread( () -> {
            try {
                // Create a server socket
                ServerSocket serverSocket = new ServerSocket(8000);
                Platform.runLater(() ->
                        ta.appendText("Server started at " + new Date() + '\n'));

                // Listen for a connection request
                Socket socket = serverSocket.accept();

                // Create data input and output streams
                DataInputStream inputFromClient = new DataInputStream(
                        socket.getInputStream());
                DataOutputStream outputToClient = new DataOutputStream(
                        socket.getOutputStream());

                // while (true) {


                    // Send result back to the client
                    //outputToClient.writeInt(flag);

                // }
                stage.setOnCloseRequest(event -> {
                    try {
                        outputToClient.writeBytes("Done");
                        serverSocket.close();
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    // Save file
                });
            }
            catch(IOException ex) {
                ex.printStackTrace();
            }
        }).start();

        /* InitApplication client = new InitApplication();
        Stage clientStage = new Stage();
        clientStage.initOwner(stage);
        client.start(clientStage); */

    }

    public static void main(String[] args)
    {

        launch();
    }





}
Celo
  • 11
  • 1

1 Answers1

3

When the server is done, just close the connection (socket.close server side).

When the client reads data (ie read function), it will return -1 or null.

Check this answer for more info : Java socket API: How to tell if a connection has been closed?

EDIT: Here is a simple way of reading and printing data.

read() returns -1 if the peer (server) closed it's socket.

byte[] buffer = new byte[1024];
int read = socket.getInputStream().read(buffer);
if(read == -1) { // Server has closed it's socket
    throw new Exception(); // Throw the exception you want
}
System.out.println(new String(buffer)); // If it reads correctly, print data
0xRyN
  • 852
  • 2
  • 13
  • But how can I verify it in the client class? I've tried witha readline but doing so GUI doesn't show – Celo Aug 25 '22 at 10:31
  • @Celo How do you read data from the socket in the client ? – 0xRyN Aug 25 '22 at 11:11
  • I don't know. That's why I have this question. – Celo Aug 25 '22 at 11:12
  • @Celo I have edited my answer with a simple way of reading data. Of course, it most cases you'd want a while(1) loop to continuously read data until socket is closed. Tell me if you have more questions – 0xRyN Aug 25 '22 at 11:23
  • the problem is I don't know where to put it in the code of the client. If I try to put it in the start method after Socket and its input and output, the application won't start. The idea could be to put an add listener, but I don't know how to implement it properly – Celo Aug 25 '22 at 11:32
  • Oh I understand. You need a thread for the networking since the main thread is running jfx. I forgot that entirely, I've never done networking with jfx. This video might help https://www.youtube.com/watch?v=_1nqY-DKP9A – 0xRyN Aug 25 '22 at 11:56
  • Perhaps consider the approach used in the [KnockKnockAsyncClient in this answer](https://stackoverflow.com/a/70888362/1155209). – jewelsea Aug 25 '22 at 17:24
  • Couple things about the code in this answer: **(1)** Typically, you read from a stream using a `while` loop until the call to `read(...)` returns `-1`. That will read until the server closes the connection. What's done in this answer only makes sense if you _know_ the next bit of the message to process is at most 1024 bytes long (i.e., you have some sort of protocol designed for you server/application). **(2)** Even if `read != -1` that doesn't mean `read == 1024`. You should use `new String(buffer, 0, read)`, and preferably also specify the `Charset` being used. – Slaw Aug 25 '22 at 17:47
  • @0xRyN I eventually solved watching the video. Thanks – Celo Sep 01 '22 at 09:22