Monday, August 11, 2014

Java/JavaFX Server link to Android Client

It's Java/JavaFX version if the server of the Android Client/Server example, run on PC.



package javafx_server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class JavaFX_Server extends Application {

    TextField textTitle;
    Label labelSys, labelPort, labelIp;
    Label labelMsg;
    CheckBox optWelcome;

    ServerSocket serverSocket;

    String message = "";

    @Override
    public void start(Stage primaryStage) {

        textTitle = new TextField();
        labelSys = new Label();
        labelPort = new Label();
        labelIp = new Label();
        labelMsg = new Label();
        optWelcome = new CheckBox("Send Welcome when connect");
        optWelcome.setSelected(true);

        labelSys.setText(
            System.getProperty("os.arch") + "/"
            + System.getProperty("os.name"));
        labelIp.setText(getIpAddress());

        VBox mainLayout = new VBox();
        mainLayout.setPadding(new Insets(5, 5, 5, 5));
        mainLayout.setSpacing(5);
        mainLayout.getChildren().addAll(textTitle,
            labelSys, labelPort, labelIp,
            optWelcome, labelMsg);

        StackPane root = new StackPane();
        root.getChildren().add(mainLayout);

        Scene scene = new Scene(root, 300, 400);

        primaryStage.setTitle("Android-er: JavaFX Server");
        primaryStage.setScene(scene);
        primaryStage.show();

        Thread socketServerThread = new Thread(new SocketServerThread());
        socketServerThread.setDaemon(true); //terminate the thread when program end
        socketServerThread.start();
    }

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

    private class SocketServerThread extends Thread {

        static final int SocketServerPORT = 8080;
        int count = 0;

        @Override
        public void run() {
            try {
                Socket socket = null;
                
                serverSocket = new ServerSocket(SocketServerPORT);
                Platform.runLater(new Runnable() {

                    @Override
                    public void run() {
                        labelPort.setText("I'm waiting here: "
                            + serverSocket.getLocalPort());
                    }
                });

                while (true) {
                    socket = serverSocket.accept();
                    count++;
                    
                    //Start another thread 
                    //to prevent blocked by empty dataInputStream
                    Thread acceptedThread = new Thread(
                        new ServerSocketAcceptedThread(socket, count));
                    acceptedThread.setDaemon(true); //terminate the thread when program end
                    acceptedThread.start();

                }
            } catch (IOException ex) {
                Logger.getLogger(JavaFX_Server.class.getName()).log(Level.SEVERE, null, ex);
            }
            
        }

    }

    private class ServerSocketAcceptedThread extends Thread {

        Socket socket = null;
        DataInputStream dataInputStream = null;
        DataOutputStream dataOutputStream = null;
        int count;

        ServerSocketAcceptedThread(Socket s, int c) {
            socket = s;
            count = c;
        }

        @Override
        public void run() {
            try {
                dataInputStream = new DataInputStream(
                    socket.getInputStream());
                dataOutputStream = new DataOutputStream(
                    socket.getOutputStream());

                //If dataInputStream empty, 
                //this thread will be blocked by readUTF(),
                //but not the others
                String messageFromClient = dataInputStream.readUTF();
                
                message += "#" + count + " from " + socket.getInetAddress()
                    + ":" + socket.getPort() + "\n"
                    + "Msg from client: " + messageFromClient + "\n";
                
                Platform.runLater(new Runnable() {
                    
                    @Override
                    public void run() {
                        labelMsg.setText(message);
                    }
                });
                
                if (optWelcome.isSelected()) {
                    
                    String msgReply = count + ": " + textTitle.getText();
                    dataOutputStream.writeUTF(msgReply);
                }
                
            } catch (IOException ex) {
                Logger.getLogger(JavaFX_Server.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException ex) {
                        Logger.getLogger(JavaFX_Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

                if (dataInputStream != null) {
                    try {
                        dataInputStream.close();
                    } catch (IOException ex) {
                        Logger.getLogger(JavaFX_Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

                if (dataOutputStream != null) {
                    try {
                        dataOutputStream.close();
                    } catch (IOException ex) {
                        Logger.getLogger(JavaFX_Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }

    }

    private String getIpAddress() {
        String ip = "";
        try {
            Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
                .getNetworkInterfaces();
            while (enumNetworkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = enumNetworkInterfaces
                    .nextElement();
                Enumeration<InetAddress> enumInetAddress = networkInterface
                    .getInetAddresses();
                while (enumInetAddress.hasMoreElements()) {
                    InetAddress inetAddress = enumInetAddress.nextElement();

                    if (inetAddress.isSiteLocalAddress()) {
                        ip += "SiteLocalAddress: "
                            + inetAddress.getHostAddress() + "\n";
                    }
                }
            }
        } catch (SocketException ex) {
            Logger.getLogger(JavaFX_Server.class.getName()).log(Level.SEVERE, null, ex);
        } 

        return ip;
    }

}


download filesDownload the files.

4 comments:

Unknown said...

I'm trying to create this exact same project. Does anything change when you're communicating between a JavaFX app and an Android app? Would I do the same socket programming on the JavaFX side as you would between two JavaFX apps and the same socket programming you would do between an Android app and another Android app?

Erik said...

Hello Kyle Bridenstine,

I suppose no change needed to talk with JavaFX Client, youca n try JavaFX client here: Java/JavaFX Client link to Android Server.

Unknown said...

Eric,

Is this appropriate for a one to many relationship i.e., have many Android clients ~30 sending data to one JavaFX server?

I did a small test and I ran two of the Android clients and one of the JavaFX servers and the server received data from both the clients but I'm wondering how this would work if I added more clients.

Erik said...

hello Kyle Bridenstine,

In my understanding:

Logically, I don't see any problem of one server service many clients, that's why it called server.

Here: Java/JavaFX example: 1 server vs 30 clients is a example of one server to 30 clients.

The point is:
Once serverSocket.accept(), start ServerSocketAcceptedThread to run on another thread to handle the communication, such that any problem in one link will not block any others.