public DumbNetworkerRouter(int port) throws Exception {
		
		// just do the reading loop in the ctor with foreverblock.
		// this doesn't do anything while there's no input. it can
		//  forget about peers after the unblocking occurs.
		
		ByteBuffer in = ByteBuffer.allocate(65536);
		ByteBuffer pingOut = ByteBuffer.allocate(64);
		
		routingTable[0] = new HashMap();
		routingTable[1] = new HashMap();
		
		InetSocketAddress isa = new InetSocketAddress(port);
		DatagramChannel channel = DatagramChannel.open();
		channel.bind(isa);
		
		while (channel.isOpen()) {
			
			// Wait for something, blocking forever
			in.clear();
			SocketAddress senderAddress = channel.receive(in);
			
			// If we received a packet, try to route it by checking
			//   whether we have the destination in any of our 
			//   routing tables.
			boolean validPacket = false;
			NetId sender = new NetId();
			NetId receiver = new NetId();
			if (senderAddress != null) {
				in.rewind();
				if (in.remaining() >= 64) {
					validPacket = true;
					++routed;
					in.get(sender.getBytes());
					in.get(receiver.getBytes());
					in.rewind();
					
					// special case: if the receiver is all zeroes, this is 
					//   a network control packet: the device is pinging the
					//   central router, and we ping back sending another
					//   packet with the sender being all zeroes.
					if (receiver.equals(pingNetId)) {
						
						// Device pinging the Router.
						
						// ping back and that's it.
						pingOut.clear();
						pingOut.put(pingNetId.getBytes()); // sender = "Pong!"
						pingOut.put(sender.getBytes()); // receiver = the Device that pinged us
						pingOut.flip();
						channel.send(pingOut, senderAddress);
						
					} else {
						
						// actual Device-to-Device packet that we have to
						//  route for them.
					
						// look it up first in the primary, since if there's
						//   an entry on both then the secondary may be out of date.
						SocketAddress receiverAddress = routingTable[prim].get(receiver);
						if (receiverAddress == null)
							receiverAddress = routingTable[sec].get(receiver);
						// if we found an address, route to it
						if (receiverAddress != null)
							channel.send(in, receiverAddress);
					}
				}
			}
			
			// Check for routing table flip every half hour
			long now = System.currentTimeMillis();
			if (now > lastPrimFlipTime + 30 * 60 * 1000) {
				lastPrimFlipTime = now; // schedule new swap
				
				int temp = prim; // swap primary and secondary indices
				prim = sec;
				sec = temp;

				System.out.println("Entries: " + (routingTable[0].size() + routingTable[1].size()) + ", Packets: " + routed);
				
				routingTable[prim] = new HashMap(); // wipe the new primary
			}
			
			// If we received a packet, refresh its sender in
			//   the primary routing table.
			if (validPacket) {
				routingTable[prim].put(sender, senderAddress);
			}
		}		
	}