2012-03-23 52 views
5

我正在使用局域网的游戏。像大多数多人游戏一样,有一个服务器 - 客户端系统。计算机A运行一个程序实例,创建一个服务器并等待;计算机B做同样的事情。现在计算机C运行该程序,我想要的是他可以将计算机A和B列为游戏服务器。我怎样才能做到这一点?
为了列出所有可用的服务器,一个简单的解决方案可能是这样的:我需要检查特定范围内的所有IP地址,并查看它们是否通过我的特定端口响应。如果是,那么游戏的一个实例正在运行,并且应该列在服务器列表中。
上述解决方案是否合适? 我已经搜索并获得这段代码:Java网络游戏:如何列出可用的服务器?

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

,但需要这么多时间,也没用。 如果这不是正确的解决方案,还有其他什么方法?

回答

1

寄使用任一发现消息:

  1. 多播(使用java.netMulticast插座)
  2. 广播(使用java.net.DatagramSocket中)到网络广播地址

有无所有的服务器监听并回复说“我在这里”并可能提供更多关于进一步连接设置的信息(服务器名称,版本,使用端口x,udp或tcp等)

0

你可以用udp来做这个;如果服务器启动,则发送广播并让al节点侦听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; 
} 

} 
+0

有没有UDP示例代码? – mehrmoudi 2012-03-23 14:40:19

+0

我添加了2个类作为示例代码;我不认为你可以将它作为一个例子运行,因为你可能会错过一些其他需要的类,但它显示了udp广播。 – Tom 2012-03-23 14:47:22

2

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

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

1

做到这一点的最佳方法是使用类似ZeroConf(也称为Bonjour)。 这是Apple在iTunes和iOS设备中用于所有网络发现的内容,以便他们可以找到对方。

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

并且在所有主要的相关语言中也有很好的支持。

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