Java网络游戏:如何列出可用的服务器?

时间:2012-03-23 13:58:22

标签: java sockets networking serversocket

我正在开发一款使用局域网的游戏。像大多数多人游戏一样,有一个服务器 - 客户端系统。计算机A运行程序实例,创建服务器并等待;计算机B做同样的事情。现在Computer 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 个答案:

答案 0 :(得分:2)

如果您在本地网络上运行,您的方法可能会花费大量时间,绝对不是最佳解决方案。

您可以通过让您的服务器定期在网络中广播其地址并让所有客户端监听它来解决此问题。在the Java Tutorials中可以找到一个很好的例子。

答案 1 :(得分:1)

使用以下任一方式发送发现消息:

  1. 多播(使用java.netMulticast套接字)
  2. 广播(使用java.net.DatagramSocket)到网络广播地址
  3. 请所有服务器监听并回复说“我在这里”以及可能有关进一步连接设置的更多信息(服务器名称,版本,使用端口x,udp或tcp等)

答案 2 :(得分:1)

执行此操作的最佳方法是使用ZeroConf(也称为Bonjour)。 这就是Apple在iTunes和iOS设备中用于所有网络发现的功能,以便他们可以找到彼此。

我已经在服务器端应用程序中实现了Linux,Windows和OSX,并取得了巨大的成功。

并且所有主要相关语言都得到了很大的支持。

没有必要重新发明这个轮子。

答案 3 :(得分:0)

你可以用udp做这个;如果服务器启动,则发出广播,让al节点侦听udp数据包。

根据要求,这是一些关于utp的示例代码;这两个课程,一个是心脏(心跳),另一个是听众。

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

}