Wirelessly connecting java to Arduino R4 through Wifi/LAN

I'm attempting to create a server using the Arduino R4 Wifi, and have a Java program on my laptop connect to this server (or vice versa, however I feel like a Arduino server with a Java client is more useful, and I already tried to swap the server and client roles and couldn't get that to work). Both of them are on the same local network. Unfortunately, when I run the java program, I get a connection refused exception. I assume it is related to the program not being able to find the Arduino server on my network.

What I have:
A windows 11 HP laptop
An Arduino R4 Wifi

Arduino server code:

#include <WiFiS3.h>
#include "secrets.h"

WiFiServer server(80);

char ssid[] = SECRET_SSID; //My Network's name stored in "secrets.h"
char pass[] = SECRET_PASS; //My Network's password stored in "secrets.h"

int status = WL_IDLE_STATUS;

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  while(!Serial) {
    ;
  }

  connectWifi();

  server.begin();

  printWiFiStatus();

}

void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress local = WiFi.localIP();
  Serial.print("Local IP Address: ");
  Serial.println(local);

  // IPAddress gateway = WiFi.gatewayIP();
  // Serial.print("Gateway IP Address: ");
  // Serial.println(gateway); //Returns 000.000.0.0 for some reason

}

void connectWifi() {
   if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  Serial.print("Creating access point named: ");
  Serial.println(ssid);

  status = WiFi.beginAP(ssid, pass);
  if (status != WL_AP_LISTENING) {
    Serial.println("Creating access point failed");
    // don't continue
    while (true);
  }
}

void loop() {
  // put your main code here, to run repeatedly:

  if (status != WiFi.status()) {
    // it has changed update the variable
    status = WiFi.status();

    if (status == WL_AP_CONNECTED) {
      // a device has connected to the AP
      Serial.println("Device connected to AP");
    } else {
      // a device has disconnected from the AP, and we are back in listening mode
      Serial.println("Device disconnected from AP");
    }
  }

  // Serial.println("Listening for a connection!");

  WiFiClient client = server.available();

  if(client) {
    Serial.println("A client has connected!");

    Serial.println(client.remoteIP());
  }

}

As you can tell, most of this code is copied from examples because 1. It works, and 2. I want to get the basics working before I move on.

Java client code:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

    int port = 80; //The arduino server's port
    String ipAddress = "192.168.4.1"; //The suppossed IPAddress of the Arduino server

    BufferedReader reader;
    BufferedWriter writer;

    public Client() {
        initConnection();
    }

    private void initConnection() {
        try {
            //Attempt to connect to the arduino server (Unlike the WiFiS3 library which consistently calls a command listening for clients, this command waits until it finds a server to connect to, holding up the rest of the program)
            Socket connection = new Socket(ipAddress, port); //This is the line that is generating the 'Timeout error'.

            System.out.println("Connected to server!");

            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));

            sendMessage();
        } catch (UnknownHostException e) {
            System.out.println("Unable to connect to server\nExiting program ):");
            e.printStackTrace();

            System.exit(0);
        } catch (IOException e) {
            System.out.println("Error when attempting to create IO streams maybe?\nExiting program ):");
            e.printStackTrace();
            
            System.exit(0);
        }
    }

    void sendMessage() {
        try {
            writer.write("Java client has connected.");
            writer.newLine();
            writer.flush();
        } catch (IOException e) {
            System.out.println("Failed to write ):");
            e.printStackTrace();
        }
    }
    
}

When running the java program, I get this output:

Error when attempting to create IO streams maybe?
Exiting program ):
java.net.ConnectException: Connection refused: connect
        at java.base/sun.nio.ch.Net.connect0(Native Method)
        at java.base/sun.nio.ch.Net.connect(Net.java:589)
        at java.base/sun.nio.ch.Net.connect(Net.java:578)
        at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:583)
        at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
        at java.base/java.net.Socket.connect(Socket.java:760)
        at java.base/java.net.Socket.connect(Socket.java:695)
        at java.base/java.net.Socket.<init>(Socket.java:564)
        at java.base/java.net.Socket.<init>(Socket.java:328)
        at Client.initConnection(Client.java:24)
        at Client.<init>(Client.java:18)
        at App.main(App.java:3)
PS C:\Users\(The director of the program)
Programs\clientForArduino>  

What I tried:

  • Before starting the client, I tested a modified version of the java program with a java server, and it successfully connected.
  • I looked through a lot of online examples, although I had trouble finding content related to my topic.
  • I attempted to assign an IPAddress for the Arduino R4 in code, however I wasn't able to get that working.
  • I changed the IPAddress in the java client code to each of the following:
    • In my wifi router's app (I have an eero), I checked for connected devices and found 2 ESPs, and used their IPAddresses, however that didn't connect. Also, when unplugging the Arduino from my computer, presumably the connected device list in the app would change, however both ESPs remained online, and no device was added or removed.
    • Turning off my windows firewall to see if the device would connect, although this still failed.

Something interesting I noticed is that a few hours after attempting to fix the problem, the Arduino's IPAddress (it's printed to the serial monitor) randomly changed from 192.168.4.1 to 192.168.4.41, although for only 2 iterations of running the program, then it reverted back to the IP ending in '.4.1'. When attempting to connect the java program using this new IPAddress, I got a new error:

Error when attempting to create IO streams maybe?
Exiting program ):
java.net.ConnectException: Connection timed out: connect
        at java.base/sun.nio.ch.Net.connect0(Native Method)
        at java.base/sun.nio.ch.Net.connect(Net.java:589)
        at java.base/sun.nio.ch.Net.connect(Net.java:578)
        at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:583)
        at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
        at java.base/java.net.Socket.connect(Socket.java:760)
        at java.base/java.net.Socket.connect(Socket.java:695)
        at java.base/java.net.Socket.<init>(Socket.java:564)
        at java.base/java.net.Socket.<init>(Socket.java:328)
        at Client.initConnection(Client.java:23)
        at Client.<init>(Client.java:18)
        at App.main(App.java:3)

Furthermore, on my wifi router's app, it says the router itself has 192.168.4.1 as the IPAddress, so the Arduino should definitely not be printing out that as its IP.
When researching, I found that Arduino R4s on default should have 192.168.4.1 as the IP, however, another google query says that the R4 WiFi should have a dynamic IP, not a static one. I'm pretty sure there's a difference between the local IP Address and the one used to connect to the internet, so perhaps that explains it?

To clarify my questions, I'm asking:

  1. Why can't the Java client find the Arduino R4 server on the network, and is it a problem relating to how IPAddresses, routers, and ports work, or is it a problem in the code?
  2. Why is the Arduino WiFi's IPAddress the same as the router, and why did it change for a short time?
  3. Is the IPAddress for the Arduino static or dynamic?

P.S. If I wrote too much, it would be helpful to tell me what to get rid of (I have no clue if this enough, too little, or too much info).

you start an Access Point on the R4 so you should connect the computer to its WiFi network first

or you want to use begin(), not beginAP()

Ah, so reading the documentation would've solved this problem

Without changing any of the code:
For the first option, I was able to connect to the arduinos network (it had the name of my original network but with a 2 after it), however I got this output on the java program when attempting to connect to it:

Error when attempting to create IO streams maybe?
Exiting program ):
java.net.ConnectException: Connection refused: connect
        at java.base/sun.nio.ch.Net.connect0(Native Method)
        at java.base/sun.nio.ch.Net.connect(Net.java:589)
        at java.base/sun.nio.ch.Net.connect(Net.java:578)
        at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:583)
        at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
        at java.base/java.net.Socket.connect(Socket.java:760)
        at java.base/java.net.Socket.connect(Socket.java:695)
        at java.base/java.net.Socket.<init>(Socket.java:564)
        at java.base/java.net.Socket.<init>(Socket.java:328)
        at Client.initConnection(Client.java:25)
        at Client.<init>(Client.java:19)
        at App.main(App.java:3)

When replacing beginAP() with begin()

This option worked and the java program was able to connect to the arduino, only problem is that the first few times I ran the programs, the client.remoteIP() call at the bottom of the arduino sketch returned 0.0.0.0, and then on my most recent run, it returned the actual IPAddress of my computer, so the inconsistency is confusing.
Anyways thanks!

don't have a Arduino R4 but this is an ESP32 TCP server

// Arduino TCP server listen for connection and display messages

//  from https://github.com/evothings/evothings-examples/blob/master/examples/arduino-led-onoff-tcp/arduinowifi/arduinowifi/arduinowifi.ino

// Include files.
#include <SPI.h>
//#include <WiFi.h>
#include "WiFi.h"

// Remove this line once you've entered WiFi SSID and password below.
//#error "WiFi SSID and password required!"

// Your network SSID (network name).
// TODO: Enter the name of your wifi network here.
char ssid[] = "xxxxxxxx";

// Your network password.
// TODO: Enter the password of your wifi network here.
char pass[] = "zzzzzzzzz";

// Your network key Index number (needed only for WEP).
int keyIndex = 0;

// Server status flag.
int status = WL_IDLE_STATUS;

// Create WiFi server listening on the given port.
WiFiServer server(20000);

void setup() {
  // Start serial communication with the given baud rate.
  // NOTE: Remember to set the baud rate in the Serial
  // monitor to the same value.
  Serial.begin(115200);

  // Wait for serial port to connect. Needed for Leonardo only
  while (!Serial) { ; }
  Serial.println("WiFi server");

  /* String version = WiFi.firmwareVersion();
  if (version != "1.1.0")
  {
    Serial.println("Please upgrade the firmware");
  }*/

  // Connect to Wifi network.
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Start the server.
  server.begin();
  // Print WiFi status.
  printWifiStatus();
}

void loop() {
  // Listen for incoming client requests.
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  Serial.print("Client connected IP ");
  Serial.print(client.remoteIP());
  Serial.print(" port ");
  Serial.println(client.remotePort());
  while (client.connected()) {
    // Read available bytes.
    while (client.available()) {
      // Read a byte and print it
      char c = client.read();
      Serial.write(c);
    }
  }
  Serial.println("Client disonnected");
}

void printWifiStatus() {
  Serial.println("WiFi status");
  // Print network name.
  Serial.print("  SSID: ");
  Serial.println(WiFi.SSID());
  // Print WiFi shield IP address.
  IPAddress ip = WiFi.localIP();
  Serial.print("  IP Address: ");
  Serial.println(ip);
  // Print the signal strength.
  long rssi = WiFi.RSSI();
  Serial.print("  Signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

and the Java client

// client which sends a message to a server using TCP

import java.io.*;
import java.util.*;
import java.net.*;

public class TCPclientS
{
        static void sendString(String remoteIPaddress, int remotePort)
        {
        Socket         socket1;        // To server.
        DataOutputStream    pw;             // To write to server.
                try
                {
                 socket1 = new Socket( remoteIPaddress, remotePort );   
                 pw = new DataOutputStream( socket1.getOutputStream() );
                 System.out.println("Server contacted OK sending " );
                 while(true)
                   {
                     String s = in.readLine();
                     pw.writeBytes(s+"\n");         // send message 
                   }  // end try
                }
                catch (UnknownHostException e) {System.err.println("SendString " +  e); }
                catch (SocketException se) {System.err.println("SendString " +  se); }
                catch (IOException e) {System.err.println("SendString " +  e); }
        }

   private final static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
   public static void main(String args[])
    {
     System.out.println("enter message to send to server");
     TCPclientS.sendString("192.168.1.211", 20000);
    }
}

ESP32 Serial Monitor displays

WiFi server

.................WiFi status
  SSID: xxxxxxxx
  IP Address: 192.168.1.211
  Signal strength (RSSI):-46 dBm
Client connected IP 192.168.1.68 port 52177
hello server
test2 sending 1234567890
test3 sending abcdefghijk

Windows Command Prompt displays

F:\Ardunio\Networking\WiFi\ESP32\TCP_client_server\TCPserver>java TCPclientS
enter message to send to server
Server contacted OK sending
hello server
test2 sending 1234567890
test3 sending abcdefghijk

may give you some ideas

Your problem may be solved now, but I think it's worth mentioning that one can use telnet on a PC to test whether a TCP server on an Arduino is able to accept TCP connections.

When you have an untested server, and an untested client, it's handy to check if the TCP server is accepting connections. One can type text in telnet and send it to the server and have the server print out what it receives.

Wireshark is also a useful tool in cases like this, but it does require some understanding of how TCP protocol is supposed to work, before one can make sense of the information it provides.

I've been having a little trouble with data transmission, so thanks

Those seem a little complicated but useful for bigger projects, thanks