Java Sockets Can't Access Server using Subnet IP Address

663 Views Asked by At

Using JDK 10, am trying to write a client / server program that will run separately on multiple computers using TCP/IP sockets.

All computers should be in same local subnet 192.168.1.x (where x can be varied between 1 and 254).

The individual servers receive a string from the client program and print out the string.

ServerThread.java:

import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.Executors;

public class ServerThread implements Runnable {

    private Socket socket;

    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        System.out.println("Connected" + socket);
        try {
            var in = new Scanner(socket.getInputStream());
            var out = new PrintWriter(socket.getOutputStream(), true);
            while (in.hasNextLine()) {
                out.println(in.nextLine());
            }
        }
        catch (Exception e) {
            System.out.println("Error:" + socket);
        }
        finally {
            try {
                socket.close();
            }
            catch (IOException e) {
            }
            System.out.println("Closed: " + socket);
        }
    }

    public static void main(String[] args) throws IOException {
        try (var listener = new ServerSocket(6500)) {
            System.out.println("Server has started...");
            var pool = Executors.newFixedThreadPool(20);
            while (true) {
                pool.execute(new ServerThread(listener.accept()));
            }
        }
    }

}

Originally, it would work with "localhost" as the hostName:

public class Client {

    public static void connect(String hostName, String portNumber) throws Exception {
        int port = Integer.parseInt(portNumber);
        try (var socket = new Socket(hostName, port)) {
            System.out.println("Enter lines of text then Ctrl+D or Ctrl+C to quit");
            var scanner = new Scanner(System.in);
            var in = new Scanner(socket.getInputStream());
            var out = new PrintWriter(socket.getOutputStream(), true);
            while (scanner.hasNextLine()) {
                out.println(scanner.nextLine());
                System.out.println(in.nextLine());
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Client.connect("localhost", "6500");
    }
}

Now when using new Socket(InetAddress.getByName(ipAddress), port), I get java.net.ConnectException: Connection refused Exception:

import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

public class Client {

    public static void connect(String iPAddress, String portNumber) throws Exception {
        int port = Integer.parseInt(portNumber);

        try (var socket = new Socket(InetAddress.getByName(iPAddress), port)) {
            System.out.println("Enter lines of text then Ctrl+D or Ctrl+C to quit");
            var scanner = new Scanner(System.in);
            var in = new Scanner(socket.getInputStream());
            var out = new PrintWriter(socket.getOutputStream(), true);
            while (scanner.hasNextLine()) {
                out.println(scanner.nextLine());
                System.out.println(in.nextLine());
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Client.connect("192.168.1.1", "6500");
    }
}

Exception in thread "main" java.net.ConnectException: Connection refused (Connection refused)
    at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:400)
    at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:243)
    at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:225)
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:402)
    at java.base/java.net.Socket.connect(Socket.java:591)
    at java.base/java.net.Socket.connect(Socket.java:540)
    at java.base/java.net.Socket.<init>(Socket.java:436)
    at java.base/java.net.Socket.<init>(Socket.java:246)
    at com.sample.Client.connect(Client.java:13)
    at com.sample.Client.main(Client.java:26)

However, when I try using "192.168.1.2", nothing happens (it doesn't even print out: Enter lines of text then Ctrl+D or Ctrl+C to quit)

And eventually, it times out by throwing this Exception:

Exception in thread "main" java.net.ConnectException: Operation timed out (Connection timed out)
    at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:400)
    at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:243)
    at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:225)
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:402)
    at java.base/java.net.Socket.connect(Socket.java:591)
    at java.base/java.net.Socket.connect(Socket.java:540)
    at java.base/java.net.Socket.<init>(Socket.java:436)
    at java.base/java.net.Socket.<init>(Socket.java:246)
    at com.sample.Client.connect(Client.java:13)
    at com.sample.Client.main(Client.java:26)


Questions:

  1. Why is it throwing this exception: java.net.ConnectException: Connection refused when using 192.168.1.1 and java.net.ConnectException: Operation timed out (Connection timed out) when using any digit other than 1 for the host (last digit), e.g. 192.168.1.2 ?

  2. Is there some other Java 10 API (e.g. reactive streams or NIO channels) that is better than just using Threads for the Server?

3

There are 3 best solutions below

1
PacificNW_Lover On BEST ANSWER

Figured it out - my router / firewall assigns different computers inside my network to different Subnet based IP addresses but doesn't necessarily will assign the second computer (subsequentially) to:

191.168.1.2

Ran an ifconfig and discovered the particular Subnet based IP address which was 192.168.1.x the real value of "x" was omitted for security reasons.

4
rxn1d On

The mistake is to assume that Socket constructor uses both IP and hostname, in reality:

new Socket("192.168.1.2", 6500)

doesn't work because it expects hostname. From this doc:

host - the host name, or null for the loopback address.
. . .
public Socket(String host,int port) throws UnknownHostException, IOException

What you have to use is:

new Socket(InetAddress.getByName("192.168.1.2"), 6500)
0
Saurabh Sharma On

I think you should also be aware of some system tools to debug at a black box level about your application in order to figure out possible issues:

I am a Linux person, so know only about Linux utilities:

"sudo netstat -tpln" to find out if your server application is listening on the desired port, and most importantly it should be listening on the IP 0.0.0.0 and not just 127.0.0.1 in order for network computers to be able to connect to it.

"sudo iptables -vnL" to find out if the firewall is not blocking external originated connections to your server applications. If this is the case, then client app on the same system where your server app resides will be able to communicate, but not the same client app on other systems on the same network.

In my experience these debugging helps resolve such issues in more than 90% of time and it is usually not a programming issue. I hope this info helps.