-1

I have a javafx desktop chess application which can be played online via sockets. One player create the GameRoom(Serversocket) and the other can join directly by entering IP address in a dialog. Instead of this method i would like to list all the available rooms and connect that way.

What would be the easiest way to implement this? I thought about putting the Server adresses in an online database like Firestore but that doesn't seem optimal for a desktop application.

The ServerSocket:

public class GameServer implements Runnable{

    private PrintWriter pw;
    private BufferedReader in;
    private ServerSocket listener;


    public GameServer(){

    }
    @Override
    public void run() {
        try {
            listener=new ServerSocket(50000);
            System.out.println("Server is listening on port 50000");
            if(in==null || pw==null){
                Socket socket=listener.accept();
                System.out.println("A player has connected");
                pw=new PrintWriter(socket.getOutputStream(),true);
                in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
              
            }
            Executors.newFixedThreadPool(1).execute(() -> {
                try {
                    OnlineGameFunctions.receiveMoveAndResign(in);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });


        }catch (IOException e){
            e.printStackTrace();
        }
    }

The client:

public class ClientSocket {

    private Socket socket;
    private PrintWriter pw;
    private BufferedReader in;


    public ClientSocket() {

    }

    public void Connect(String ip, int port) throws IOException {
        if(in==null || pw==null){
            socket=new Socket(ip,port);
            in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            pw=new PrintWriter(socket.getOutputStream(),true);
        }

        
        Executors.newFixedThreadPool(1).execute(() -> {
            try {
                OnlineGameFunctions.receiveMoveAndResign(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

    }

}
Mizsi
  • 1
  • 1

1 Answers1

0

You can manually try to connect to possible ip addresses in your network, this answer is a combination of answers from SO and i will add links to them in the end of the post.

You first need to get your Lan Ip Address and its prefix length, then use them to make a list of all possible ip addresses (used commons-net), then divide those ip addresses on multiple threads, each thread will loop through a portion of the IP's and try to connect to each one of them, if connection succeeds => add the ip to results.

I have written this code (well most of it) and tested it on my machine by creating a socketServer and it returned my ip so i guess it works :

public class SocketScan {
    public static void main(String[] args) throws Exception {
        System.out.println(scan(50000));
    }

    public static List<String> scan(int port) throws Exception {
        System.out.println("scanning for servers...");
        ArrayList<String> res = new ArrayList<String>();

        // get your lan ip
        InterfaceAddress addr = getLanIp();
        String myIp = addr.getAddress().getHostAddress() + "/" + addr.getNetworkPrefixLength();

        // list all possible ip addresses using your ip and mask
        SubnetUtils utils = new SubnetUtils(myIp);
        String[] allIps = utils.getInfo().getAllAddresses();

        // split all ips on a number of threads
        // and try to connect to each one of them
        int threadCount = 24;
        Thread[] threads = new Thread[threadCount];

        int threadSize = allIps.length / threadCount;

        for (int i = 0; i < threadCount; i++) {
            final int index = i;
            threads[i] = new Thread() {
                public void run() {
                    int start = threadSize * index;
                    int end = threadSize * (index + 1);
                    for (int j = start; j < (index == threadCount - 1 ? allIps.length : end); j++) {
                        String ip = allIps[j];
                        if(checkIp(ip, port)) {
                            res.add(ip);
                        }
                    }
                }
            };
        }

        //start all threads
        for (Thread thread : threads) {
            thread.start();
        }

        //wait for all threads to finish
        for (Thread thread : threads) {
            thread.join();
        }

        return res;
    }

    //check if a connection to this ip is possible
    public static boolean checkIp(String ip, int port) {
        try {
            Socket socket = new Socket();
            socket.connect(new InetSocketAddress(ip, port), 150);
            socket.close();
            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    //This method loops through your network interfaces and returns
    //the first address that is ipv4 and not loopback
    public static InterfaceAddress getLanIp() throws Exception {
        for (final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces
                .hasMoreElements();) {
            final NetworkInterface cur = interfaces.nextElement();

            if (cur.isLoopback()) {
                continue;
            }

            for (final InterfaceAddress addr : cur.getInterfaceAddresses()) {
                final InetAddress inet_addr = addr.getAddress();
                if (!(inet_addr instanceof Inet4Address)) {
                    continue;
                }
                return addr;
            }
        }
        return null;
    }
}

Note that this is gonna take some time to finish (about 3 seconds on my machine with my /24 subnet), if you don't want to wait for all ips to be checked you can pass a consumer to handle an ip after the check is successful

Used answers

Ip address scanner this doesn't take network subnet into consideration

Getting LAN ip just replaced printing with return

Getting possible Ip addresses

checking ip address

SDIDSA
  • 894
  • 10
  • 19
  • Thanks for your answer, this works very well on my LAN network. But my goal is to list avalaible servers from other networks too. – Mizsi Oct 25 '21 at 07:09
  • you will have to register open rooms in a server with a fixed public ip and query it for the list of open rooms. besides, you're gonna need some special setup on the socket server side like port forwarding before you can connect to it from other networks. – SDIDSA Oct 25 '21 at 08:40