2012-03-23 53 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,並取得了巨大的成功。

並且在所有主要的相關語言中也有很好的支持。

沒有必要重新發明這個輪子。