/* * Copyright 2013-2014 Cel Skeggs * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.net; import java.io.IOException; import ccre.concurrency.ReporterThread; import ccre.log.Logger; /** * A simple thread to allow easy writing of servers without creating a custom * thread to receive new client connections. * * @author skeggsc */ public abstract class ConnectionReceiverThread extends ReporterThread { /** * The port that the server is started on. */ private final int port; /** * The name of this thread. */ private final String thrName; /** * Create a new ConnectionReceiverThread with the specified thread name and * port. * * @param name The thread name. This is passed directly to ReporterThread. * @param port This is the TCP port to host on. */ public ConnectionReceiverThread(String name, int port) { super(name); this.thrName = name; this.port = port; } @Override protected final void threadBody() throws IOException { Logger.fine("About to listen on " + port); ServerSocket sock; try { sock = Network.bind(port); } catch (IOException e) { if (e.getClass().getName().equals("java.net.BindException")) { Logger.warning("Failed to bind to port " + port + "."); return; } throw e; } while (true) { final ClientSocket conn = sock.accept(); new ReporterThread(thrName + "-client") { @Override protected void threadBody() throws Throwable { try { handleClient(conn); } finally { conn.close(); } } }.start(); } } /** * Handle a client. This is run in a new thread, so you don't need to worry * about holding up other threads or accidentally terminating all * connections if an error occurs. The connection will be closed * automatically once this method returns or throws an error. * * @param conn The client connection. * @throws Throwable If something bad happens. */ protected abstract void handleClient(ClientSocket conn) throws Throwable; }