Сетевая игра Java: Как составить список доступных серверов? - PullRequest
5 голосов
/ 23 марта 2012

Я работаю над игрой, которая использует локальную сеть.Как и в большинстве многопользовательских игр, существует система сервер-клиент.Компьютер A запускает экземпляр программы, создает сервер и ждет;Компьютер B делает то же самое.Теперь компьютер C запускает программу, и я хочу, чтобы он мог видеть компьютеры A и B в списке как игровые серверы.Как я могу это сделать?Чтобы перечислить все доступные серверы, простое решение может быть таким: мне нужно проверить все IP-адреса в определенном диапазоне и посмотреть, отвечают ли они через мой конкретный порт или нет.Если да, то на нем запущен экземпляр игры, который должен быть указан в списке серверов.Является ли решение, описанное выше, хорошим?Я искал и получил этот код:

public void checkHosts(String subnet){
    int timeout=1000;
    for (int i=1;i<254;i++){
        String host=subnet + "." + i;
            if (InetAddress.getByName(host).isReachable(timeout)){
                System.out.println(host + " is reachable");
            }
    }
}

, но это занимает так много времени и бесполезно.Если это не правильное решение, каковы другие способы?

Ответы [ 4 ]

2 голосов
/ 23 марта 2012

Если вы работаете в локальной сети, ваш метод может занять огромное количество времени и определенно не является лучшим решением.

Вы можете решить эту проблему, периодически передавая своим серверам адреса в сети.и пусть все клиенты прислушаются к этому.Хороший пример можно найти в Учебниках Java .

1 голос
/ 23 марта 2012

Лучший способ сделать это с чем-то вроде ZeroConf (также известный как Bonjour ).Это то, что Apple использует для всех своих сетевых обнаружений на устройствах iTunes и iOS, чтобы они могли находить друг друга.

Я с большим успехом реализовал Linux, Windows и OSX в серверных приложениях.1008 * И есть большая поддержка на всех основных языках.

Нет необходимости заново изобретать это колесо.

1 голос
/ 23 марта 2012

Отправьте сообщение об обнаружении, используя либо:

  1. многоадресная рассылка (используйте сокет java.netMulticast)
  2. широковещательная рассылка (используйте java.net.DatagramSocket) на широковещательный адрес сети

Пусть все серверы прослушают это и ответят: «Я здесь» и, возможно, дополнительную информацию для дальнейшей настройки соединения (имя сервера, версия, использование порта x, udp или tcp и т. Д.)

0 голосов
/ 23 марта 2012

вы можете использовать UDP для этого;отправьте широковещательную рассылку, если сервер включен, и пусть все узлы прослушивают пакеты udp.

В соответствии с запросом приведен пример кода на utp;тезисы - 2 класса, один - сердце (которое бьется), а другой - слушатель.

public class Heart extends Observable implements Runnable {

private String groupName = "229.5.38.17";
private int port = 4567;
MulticastSocket multicastSocket;
DatagramPacket datagramPacket;

public Heart(int connectionListenerPort, Observer...observers) {
    for(Observer observer : observers) {
        this.addObserver(observer);
    }
    try {
        multicastSocket = new MulticastSocket();
        InetAddress group = InetAddress.getByName(groupName);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(new Beat(connectionListenerPort));
        objectOutputStream.flush();
        objectOutputStream.close();
        byte[] buf = byteArrayOutputStream.toByteArray();
        datagramPacket = new DatagramPacket(buf, buf.length, group, port);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public void run() {
    while(true) {
        beat();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private void beat() {
    try {
        multicastSocket.send(datagramPacket);
        message(new Message(TYPE.INFO, KEY.MESSAGE, "Heart beat sent."));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void message(Message message) {
    setChanged();
    notifyObservers(message);
}

}

public class BeatListener extends Observable implements Runnable {

private boolean run = true;
private String groupName = "229.5.38.17";
MulticastSocket multicastSocket;
private Network network;

public BeatListener(Network network, Observer... observers) {
    for(Observer observer : observers) {
        addObserver(observer);
    }
    try {
        multicastSocket = new MulticastSocket(4567);
        multicastSocket.joinGroup(InetAddress.getByName(groupName));
    } catch (IOException e) {
        error(e);
        e.printStackTrace();
    }
    this.network = network;
}

@Override
public void run() {
    while(run) {
        DatagramPacket datagramPacket = new DatagramPacket(new byte[1500], 1500);
        try {
            multicastSocket.receive(datagramPacket);
            if(!isLocalhost(datagramPacket.getAddress().getHostAddress())) {
                Beat beat = getBeat(datagramPacket);
                if(beat != null) {
                    network.setPeer(new Peer(datagramPacket.getAddress(), beat.getConnectionListenerPort()));
                    message(new Message(TYPE.NETWORK, KEY.NETWORK, network));
                }
            }
        } catch (IOException e) {
            error(e);
            e.printStackTrace();
        }
    }
}

private void message(Message message) {
    setChanged();
    notifyObservers(message);
}

private void error(Exception e) {
    message(new Message(TYPE.ERROR, KEY.MESSAGE, e.getClass().getSimpleName()));
}

public void stop() {
    run = false;
}

private boolean isLocalhost(String hostAddress) {
    boolean isLocalhost = false;
    Enumeration<NetworkInterface> networkInterfaces;
    try {
        networkInterfaces = NetworkInterface.getNetworkInterfaces();
        if(networkInterfaces != null) {
            OUTER:
            while(networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
                if(inetAddresses != null) {
                    while(inetAddresses.hasMoreElements()) {
                        InetAddress inetAddress = inetAddresses.nextElement();
                        if(hostAddress.equals(inetAddress.getHostAddress())) {
                            isLocalhost = true;
                            break OUTER;
                        }
                    }
                }
            }
        }
    } catch (SocketException e) {
        error(e);
        e.printStackTrace();
    }
    return isLocalhost;
}

private Beat getBeat(DatagramPacket datagramPacket) {
    Beat beat = null;
    byte[] data = datagramPacket.getData();
    if(data != null) {
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data));
            beat = (Beat)objectInputStream.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    return beat;
}

}
...