package robombs.clientserver; import java.net.*; import java.util.*; /** * Simple server browser that listens on a specified UDP port for servers broadcasting their connection data on that port. */ public class ServerBrowser { private int port=0; private boolean exit=false; private boolean running=false; private List<ServerEntry> servers=new ArrayList<ServerEntry>(); private List<DataChangeListener> dataChangeListener=new ArrayList<DataChangeListener>(); /** * Creates a new ServerBrowser that will listen on a speficied UDP-port for servers to broadcast their data. This prepares the browser, it doesn't start it. * @param port the UDP port to use */ public ServerBrowser(int port) { this.port=port; } /** * Adds a new DataChangesListener to the browser. The listener will be notified if the server list changes, i.e. * if servers get removed or added. * @param listener the listener */ public void addListener(DataChangeListener listener) { dataChangeListener.add(listener); } /** * Starts the browser. */ public void startBrowser() { new Thread(new BrowserThread()).start(); } /** * Stops the browser. */ public void stopBrowser() { exit=true; } /** * Returns the current list of servers that this browser has found. * @return List the server list */ public List<ServerEntry> getServerList() { synchronized(servers) { return new ArrayList<ServerEntry>(servers); } } /** * Notify the listeners... */ private void fireEvent() { for (Iterator<DataChangeListener> itty = dataChangeListener.iterator(); itty.hasNext(); ) { DataChangeListener dcl = itty.next(); dcl.dataChanged(getServerList()); } } /** * The thread that listens on the port for servers to send their data. */ private class BrowserThread implements Runnable { public void run() { try { running=true; DatagramSocket bsock=new DatagramSocket(port); bsock.setSoTimeout(3000); byte[] buffer = new byte[1000]; DatagramPacket dpr = new DatagramPacket(buffer, buffer.length); while(!exit) { boolean ok=false; try { bsock.receive(dpr); ok=true; }catch(SocketTimeoutException e) { } if (ok) { byte[] data = new byte[dpr.getLength()-2]; System.arraycopy(dpr.getData(), 2, data, 0, data.length); DataContainer dc = new DataContainer(data, false); ServerEntry se = new ServerEntry(dc.getNextString(), dpr.getAddress(), dc.getNextInt(), dc.getNextInt()); boolean found = false; synchronized (servers) { for (Iterator<ServerEntry> itty = servers.iterator(); itty.hasNext(); ) { ServerEntry st = itty.next(); if (st.equals(se)) { st.setClientCount(se.getClientCount()); st.touch(); if (se.getClientCount()==-9999) { // -9999 flags that the server is going down. itty.remove(); st.setClientCount(0); NetLogger.log("ServerBrowser: Server " + st.getName() + " removed by server's request!"); } found = true; } } if (!found && se.getClientCount()!=-9999) { // Don't add it again, if it was a removal request NetLogger.log("ServerBrowser: Server " + se.getName() + " added!"); servers.add(se); } } } synchronized (servers) { for (Iterator<ServerEntry> itty = servers.iterator(); itty.hasNext(); ) { ServerEntry st = itty.next(); if (st.isOld()) { NetLogger.log("ServerBrowser: Server " + st.getName() + " removed!"); itty.remove(); } } fireEvent(); } } } catch(Exception e) { NetLogger.log("Can't start server browser due to: "); e.printStackTrace(); } running=false; } } public boolean isRunning() { return running; } }