首页 > 解决方案 > 列出套接字应用程序的游戏房间

问题描述

我有一个 javafx 桌面国际象棋应用程序,可以通过套接字在线播放。一个玩家创建 GameRoom(Serversocket),另一个玩家可以通过在对话框中输入 IP 地址直接加入。而不是这种方法,我想列出所有可用的房间并以这种方式连接。

实现这一点的最简单方法是什么?我曾考虑将服务器地址放在像 Firestore 这样的在线数据库中,但这对于桌面应用程序来说似乎不是最佳选择。

服务器套接字:

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();
        }
    }

客户端:

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();
            }
        });

    }

}

标签: javadatabasesocketsjavafx

解决方案


您可以手动尝试连接到网络中可能的 IP 地址,这个答案是来自 SO 的答案的组合,我将在帖子末尾添加指向它们的链接。

您首先需要获取您的局域网 IP 地址及其前缀长度,然后使用它们列出所有可能的 IP 地址(使用commons-net),然后将这些 IP 地址划分到多个线程上,每个线程将循环通过一部分IP 并尝试连接到其中的每一个,如果连接成功 => 将 IP 添加到结果中。

我已经编写了这段代码(大部分代码)并通过创建 socketServer 在我的机器上对其进行了测试,它返回了我的 ip,所以我猜它可以工作:

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;
    }
}

请注意,这需要一些时间才能完成(在我的机器上使用我的 /24 子网大约需要 3 秒),如果您不想等待检查所有 ip,您可以在检查后通过消费者来处理 ip是成功的

用过的答案

IP 地址扫描器,这不考虑网络子网

获取 LAN ip只是将打印替换为返回

获取可能的 IP 地址

检查IP地址


推荐阅读