【问题标题】:Java network game: How to list available servers?Java 网络游戏:如何列出可用服务器?
【发布时间】:2012-04-08 02:05:03
【问题描述】:

我正在开发一款使用局域网的游戏。像大多数多人游戏一样,有一个服务器-客户端系统。计算机 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");
            }
    }
}

但是它需要很多时间并且没用。 如果这不是正确的解决方案,还有哪些其他方法?

【问题讨论】:

    标签: java sockets networking serversocket


    【解决方案1】:

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

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

    所有主要的相关语言也都得到了很好的支持。

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

    【讨论】:

      【解决方案2】:

      您可以为此使用 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;
      }
      
      }
      

      【讨论】:

      • 我添加了 2 个类作为示例代码;我不认为你可以只运行它作为示例,因为你可能会错过一些其他需要的类,但它显示 udp 广播。
      【解决方案3】:

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

      1. 多播(使用 java.netMulticast 套接字)
      2. 广播(使用 java.net.DatagramSocket)到网络广播地址

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-20
          • 2013-11-12
          • 2012-07-26
          • 1970-01-01
          • 2017-10-09
          • 1970-01-01
          • 2014-04-12
          相关资源
          最近更新 更多