Tuesday, 22 January 2019

Sockets - Java to Java - Sockets programming

Like most great languages Java has the ability open and read/write from/to sockets, a TCP/IP programming protocol lower than HTTP. This month I have been demonstrating Excel VBA acting as one endpoint for a Sockets connection (specifically communicating to Redis). That Excel VBA can talk to sockets means we can get VBA to talk to Java. I will write an VBA to Java article shortly but first it is better to write a Java to Java sockets application to see what is involved.

(And the more attentive amongst you will spot that I have just written a Ruby to Ruby sockets application so let's see if its true than Java is more verbose.)

The following code is a simple single-thread app (if you want multi-threaded, see the original article as we are here to demonstrate the sockets only.

JavaSocketsCalcClient.java

So this is the client code which simply reads a line of input in the form of a sum like "1+3" (actually you can do subtraction, divide and multiply), calls the server via sockets and then prints the return.

Here is the code for the file JavaSocketsCalcClient.java

//With thanks to https://www.baeldung.com/a-guide-to-java-sockets
import java.net.*;
import java.io.*;

public class JavaSocketsCalcClient {
    private Socket clientSocket;
    private PrintWriter out;
    private BufferedReader in;

    public void startConnection(String ip, int port) {
        try {
            clientSocket = new Socket(ip, port);
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        } catch (Exception exc) {
            System.out.println(exc.getMessage());
        }
    }

    public String sendMessage(String msg) {
        try {
            out.println(msg);
            String resp = in.readLine();
            return resp;
        } catch (Exception exc) {
            System.out.println(exc.getMessage());
            return "";
        }
    }

    public void stopConnection() {
        try {
            in.close();
            out.close();
            clientSocket.close();
        } catch (Exception exc) {
            System.out.println(exc.getMessage());
        }
    }

    public static void main(String[] args) {
        try {
            GreetClient client = new GreetClient();
            client.startConnection("127.0.0.1", 6666);
            InputStreamReader reader = new InputStreamReader(System.in);
            BufferedReader in = new BufferedReader(reader);
            while (true) {
                System.out.println(client.sendMessage(in.readLine()));
            }
        } catch (Exception exc) {
            System.out.println(exc.getMessage());
        }
    }
}

So compile and run you need the following commands (and I'm surprised we do not use the .class suffix in the second to be honest).

N:\java\javaSockets>javac JavaSocketsCalcClient.java
N:\java\javaSockets>java JavaSocketsCalcClient

JavaSocketsCalcServer.java

This is the server which takes the sum string e.g. "1+3" and then parses it with a regular expression before calculating and returning the answer to the client.

//With thanks to https://www.baeldung.com/a-guide-to-java-sockets
import java.net.*;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaSocketsCalcServer {
    private ServerSocket serverSocket;
    private Socket clientSocket;
    private PrintWriter out;
    private BufferedReader in;

    public void start(int port) {
        try {
            serverSocket = new ServerSocket(port);
            System.out.println("Running on port " + port);

            String pattern = "(\\d+)\\s*(\\+|\\*|-|\\/)\\s*(\\d+)";

            // Create a Pattern object
            Pattern r = Pattern.compile(pattern);

            while (true) {

                clientSocket = serverSocket.accept();
                out = new PrintWriter(clientSocket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                try {
                    System.out.println("waiting to read line ...");
                    String sum = in.readLine();
                    System.out.println("Received text:" + sum);
                    // Now create matcher object.
                    Matcher m = r.matcher(sum);
                    if (m.find()) {
                        Float arg0 = Float.parseFloat(m.group(1));
                        String op = m.group(2);
                        Float arg1 = Float.parseFloat(m.group(3));
                        String resp = "";
                        if (op.equals("+")) {
                            resp = String.valueOf(arg0 + arg1);
                        } else if (op.equals("-")) {
                            resp = String.valueOf(arg0 - arg1);
                        } else if (op.equals("*")) {
                            resp = String.valueOf(arg0 * arg1);
                        } else if (op.equals("/")) {
                            resp = String.valueOf(arg0 / arg1);
                        } else {
                            out.println("could not match operand");
                        }

                        out.println(sum + " = " + resp);
                    } else {
                        out.println("does not look calculable");
                    }
                } catch (Exception exc) {
                    System.out.println(exc.getMessage());
                }
            }
        } catch (Exception exc) {
            System.out.println(exc.getMessage());
        }
    }

    public void stop() {
        try {
            in.close();
            out.close();
            clientSocket.close();
            serverSocket.close();
        } catch (Exception exc) {
            System.out.println(exc.getMessage());
        }
    }

    public static void main(String[] args) {
        GreetServer server = new GreetServer();
        server.start(6666);
    }
}

So in a separate console window, do the following

N:\java\javaSockets>javac JavaSocketsCalcServer.java
N:\java\javaSockets>java JavaSocketsCalcServer

Here is a screenshot of the two consoles running and communicating

Keen observers of the code will realise they both run in endless loops. Never mind about that, I simply wanted to get the servers running and demonstrable.

What's Next?

So what's next is some code which shows VBA calling this Java server and also the Ruby server from the previous article to illustrate VBA can call Java and Ruby despite them not having a COM APIs.

No comments:

Post a Comment