package com.cardshifter.server.model;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import com.cardshifter.server.main.ServerConfiguration;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import com.cardshifter.server.clients.ClientSocketHandler;
public class ServerSock implements ConnectionHandler {
private static final Logger logger = LogManager.getLogger(ServerSock.class);
private final AtomicInteger activeConnections = new AtomicInteger(0);
private final AtomicInteger threadCounter = new AtomicInteger(0);
private final ExecutorService executor;
private final Server server;
private final Thread thread;
private final ServerSocket serverSocket;
/**
* Constructor.
* @param server Server instance
* @param config Uses the value of {@code config.getPortSocket} as port. If {@code port == 0} any available port is
* used and the real port number is set in {@code config} before returning.
* @throws IOException
*/
public ServerSock(Server server, ServerConfiguration config) throws IOException {
this.server = server;
this.executor = Executors.newCachedThreadPool(r -> new Thread(r, "Conn-" + threadCounter.getAndIncrement()));
// If port = 0, use any open port. Set the config port to the real port used.
this.serverSocket = new ServerSocket(config.getPortSocket());
config.setPortSocket(serverSocket.getLocalPort());
this.thread = new Thread(this::run);
}
private void run() {
try {
int maxConnections = 0;
while (activeConnections.incrementAndGet() < maxConnections || maxConnections == 0) {
logger.info("Waiting for client nr: " + activeConnections.get() + "...");
Socket client = serverSocket.accept();
ClientSocketHandler clientHandler = new ClientSocketHandler(this.server, client);
logger.info("Incoming connection from " + client.getRemoteSocketAddress());
if (thread.isInterrupted()) {
logger.info("ServerSocket thread interrupted, shutting down.");
break;
}
this.server.newClient(clientHandler);
Future<?> future = executor.submit(clientHandler);
}
}
catch (Exception e) {
logger.error("Error in ServerSocket", e);
}
}
@Override
public void start() {
logger.info("Starting Socket server at port " + serverSocket.getLocalPort() + "...");
thread.start();
logger.info("Socket server started.");
}
@Override
public void shutdown() {
thread.interrupt();
logger.info("Shutting down ServerSock Executor");
executor.shutdownNow();
logger.info("Shutting down serverSocket");
try {
serverSocket.close();
} catch (IOException e) {
logger.error("IOException when closing ServerSocket", e);
}
}
}