Advertising server on lan

My networking code is fine, but I have to input the servers ip manual for the client. is there some way to detect what servers are currently running on the lan?

I have seen this done in other games, I have tried looking it up in good, but i think my keywords are wrong.

I have never tried this, but I pondered the question myself and came up with this potential answer:

Every IP on a LAN has the same first 3 numbers, only the last number changes. So perhaps they scan every possible last number (256 options) and see which one connect.

You might want to look into broadcast UDP packets.

cool thanx guys.
because the game im working on is TCP ill try the scan idea

This is not true, you must look both to IP and netmask. There can be various combinations. Remember LAN is the same as internet, it just (mostly) uses one of three reserved IP ranges (192.168.x.x, 10.x.x.x, 172.16.0.0-172.31.255.255). You should use special IP adress 255.255.255.255 for broadcast (or derived one from IP and netmask, where you replace host bits with all 1s).

would you know any tutorials on the net that explain this in detail?

I monitored the traffic on wc3 when hosting a server, and yeah its creats another UDP port. So i guess ill read up on multicast sockets. Thanx for all the help

Most comercial games use a registry server. This is a central server where any game server will register itself when it comes online. This is where you find your lobbys, chat areas, etc. All the client has to do then is have the registry server’s IP address.

But what about clients that can’t connect over the internet, and therefore to this registry server?

It’s two different use cases.

CJ is talking about games that allow internet play, the registry server is used to allow players to find games that have been added to the central registry (counter strike is a good example).

bobjob, I think, is talking about LAN games as opposed to internet based play. Most commercial games that support LAN play also use multicast to allow players to broadcast on a common multicast address and hence find each other on the network.

The multicast approach doesn’t work with internet games because most routers are configured to not allow re-broadcast multicast packets. So in most cases the multicast will only reach machines on the same subnet.

Using TCP for game play but using multicast/broadcast UDP for discovery is very common.

Kev


public class NetworkDiscovery
{
   private static final long default_broadcast_interval = 2000;
   private static final String default_broadcast_host = "255.255.255.255";
   private static final int default_broadcast_port = 8008;

   public static final void broadcastService(String serviceName, InetSocketAddress broadcastAboutService) throws IOException
   {
      InetSocketAddress broadcastAddress = new InetSocketAddress(InetAddress.getByName(default_broadcast_host), default_broadcast_port);
      NetworkDiscovery.broadcastService(serviceName, broadcastAddress, broadcastAboutService, default_broadcast_interval, -1);
   }

   public static final void broadcastService(String serviceName, InetSocketAddress broadcastAddress, InetSocketAddress broadcastAboutService, long interval, int times) throws IOException
   {
      InetSocketAddress bindAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
      DatagramSocket socket = new DatagramSocket(bindAddress);

      byte[] packetData;
      {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         DataOutputStream dos = new DataOutputStream(baos);
         dos.writeUTF(serviceName);
         dos.writeUTF(broadcastAboutService.getHostName());
         dos.writeInt(broadcastAboutService.getPort());
         dos.flush();
         packetData = baos.toByteArray();
      }

      try
      {
         for (int i = 0; i < times || times == -1; i++)
         {
            socket.send(new DatagramPacket(packetData, 0, packetData.length, broadcastAddress));

            try
            {
               Thread.sleep(interval);
            }
            catch (InterruptedException exc)
            {
               exc.printStackTrace();
            }
         }
      }
      catch (Exception exc)
      {
         exc.printStackTrace();
      }
   }

   /**
    * Listens for UDP packets at the specified <code>port</code>.

    * Only returns when the received packet has the specified <code>name</code>.

    * This way multiple broadcasting sockets per UDP port are supported
    */

   public static final InetSocketAddress discoverService(String serviceName)
   {
      return NetworkDiscovery.discoverService(serviceName, default_broadcast_port, 10, (int)default_broadcast_interval * 4);
   }

   public static final InetSocketAddress discoverService(String serviceName, int port, int maxTries, int socketTimeout)
   {
      try
      {
         int packetLength = 1024;

         DatagramSocket socket = new DatagramSocket(port, InetAddress.getLocalHost());
         DatagramPacket packet = new DatagramPacket(new byte[packetLength], 0, packetLength);

         socket.setSoTimeout(socketTimeout);

         for (int i = 0; i < maxTries; i++)
         {
            try
            {
               socket.receive(packet);
            }
            catch (IOException exc)
            {
               exc.printStackTrace();
               break;
            }

            ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData(), packet.getOffset(), packet.getLength());
            DataInputStream dis = new DataInputStream(bais);

            String theServiceName = dis.readUTF();
            if (!theServiceName.equals(serviceName))
               continue;

            String notifyHost = dis.readUTF();
            int notifyPort = dis.readInt();
            return new InetSocketAddress(notifyHost, notifyPort);
         }
      }
      catch (IOException exc)
      {
         exc.printStackTrace();
      }

      throw new NoSuchServiceException("Service \"" + serviceName + "\" not found");
   }

   public static class NoSuchServiceException extends RuntimeException
   {
      public NoSuchServiceException(String msg)
      {
         super(msg);
      }
   }
}

yeah.

thanx for the example riven, cant wait to go through it.

i tested the code, and its works really well.

just in case anyone is interested in using the code, I fixed/changed a few things:
broadcast address to “255.255.255.255”
interval to be alot higher, i was comparing it to other comercial game delays, 6000 seems decent enough
new Socket(serviceAddress); needs to be changed to: new Socket(serviceAddress.getHostName(), serviceAddress.getPort());

thanx again Riven that really saved me alot of time.

I updated the code a bit for usability.

Wow, excellent job on the code update!

  • gathers Riven’s code ;D *

http://java.sun.com/javase/6/docs/api/java/net/NetworkInterface.html#getInterfaceAddresses()
and
http://java.sun.com/javase/6/docs/api/java/net/InterfaceAddress.html#getBroadcast()
Should get the broadcast adress. however requires java 6 and up, and 255.255.255.255 should always work. Well as far as ipv4 goes.
For ipv6 use multicast. Perhaps we should code a multicast version to ensure that it works on both ipv4 and 6 networks.

edit. I suppose you could also go for ethernet broadcast but I’m not sure if you can do that from java as it’s (good)support for everything lower then ip is absent(ping anyone?).

There is an obscure isReachable() method somewhere that ‘might use ping’, according to the spec. (sigh)

http://java.sun.com/j2se/1.5.0/docs/api/java/net/InetAddress.html#isReachable(int)

Kinda useless if you want to figure out the most responsive server / ‘closest’ server.