All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lowentry.ue4.classes.sockets.SocketServer Maven / Gradle / Ivy

There is a newer version: 9.9.9.DELETED
Show newest version
package lowentry.ue4.classes.sockets;


import java.io.PrintStream;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.function.Consumer;

import lowentry.ue4.classes.internal.CachedTime;
import lowentry.ue4.library.LowEntry;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroClient;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroSelector;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroServer;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.events.PyroServerListener;
import lowentry.ue4.libs.pyronet.lowentry.pyronet.udp.PyroServerUdp;
import lowentry.ue4.libs.pyronet.lowentry.pyronet.udp.event.PyroServerUdpListener;


public class SocketServer implements Iterable
{
	public static boolean												IS_DEBUGGING							= false;
	public static PrintStream											DEBUGGING_PRINTSTREAM					= System.out;
	
	
	private static final int											NEW_CONNECTIONS_QUEUE_SIZE				= 500;
	
	
	protected final PyroServer											server;
	protected final List									clients									= new ArrayList();
	
	protected final PyroServerUdp										serverUdp;
	protected final HashMap	serverUdpClientHandlers					= new HashMap();
	protected final ByteBuffer											serverUdpNetworkBuffer;
	
	protected final int													serverPortTcp;
	protected final int													serverPortUdp;
	
	protected final SocketServerListener								socketListener;
	
	protected long														lastHandshakingClientHandlerValidation	= CachedTime.nanoTime();
	protected final LinkedHashSet			handshakingClientHandlers				= new LinkedHashSet();
	
	protected final ByteBuffer											clientDataBuffer						= ByteBuffer.allocateDirect(PyroSelector.BUFFER_SIZE);
	
	
	/**
	 * Causes debug messages to be printed.
*
* Only call this function if you have not yet created any SocketServers, and only call this function on the same thread you will create your SocketServers in, otherwise you might run into threading problems. */ public static void setDebuggingEnabled() { SocketServer.IS_DEBUGGING = true; } /** * Causes debug messages to be printed to the given PrintStream.
*
* Only call this function if you have not yet created any SocketServers, and only call this function on the same thread you will create your SocketServers in, otherwise you might run into threading problems. */ public static void setDebuggingEnabled(PrintStream printstream) { SocketServer.IS_DEBUGGING = true; SocketServer.DEBUGGING_PRINTSTREAM = printstream; } public SocketServer(boolean acceptExternalConnections, int portTcp, SocketServerListener listener) throws Throwable { this.serverPortTcp = portTcp; this.serverPortUdp = 0; this.socketListener = listener; PyroSelector selector = new PyroSelector(); this.server = selector.listen(acceptExternalConnections, portTcp, NEW_CONNECTIONS_QUEUE_SIZE, createServerListener()); this.serverUdp = null; this.serverUdpNetworkBuffer = null; } public SocketServer(boolean acceptExternalConnections, int portTcp, int portUdp, SocketServerListener listener) throws Throwable { this.serverPortTcp = portTcp; this.serverPortUdp = ((portUdp <= 0) ? 0 : portUdp); this.socketListener = listener; PyroSelector selector = new PyroSelector(); this.server = selector.listen(acceptExternalConnections, portTcp, NEW_CONNECTIONS_QUEUE_SIZE, createServerListener()); this.serverUdp = ((portUdp <= 0) ? null : new PyroServerUdp(acceptExternalConnections, portUdp, createServerUdpListener())); this.serverUdpNetworkBuffer = ((serverUdp == null) ? null : ByteBuffer.allocate(PyroSelector.BUFFER_SIZE)); } protected PyroServerListener createServerListener() { return new PyroServerListener() { @Override public void acceptedClient(final PyroClient client) { SocketServer socketServer = SocketServer.this; SocketClient socketClient = new SocketClient(socketServer, client); SocketServerClientHandler clientHandler = new SocketServerClientHandler(socketListener, socketServer, socketClient); client.setListener(clientHandler); clientHandler.connectedClient(client); } }; } protected PyroServerUdpListener createServerUdpListener() { return new PyroServerUdpListener() { @Override public void receivedDataUdp(SocketAddress client, ByteBuffer data) { SocketServerClientHandler clientHandler = serverUdpClientHandlers.get(client); if(clientHandler != null) { clientHandler.receivedDataUdp(client, data); } } }; } protected void addUdpClient(SocketServerClientHandler clientHandler) { SocketAddress clientUdp = clientHandler.socketClient.clientUdpAddress; if(clientUdp != null) { serverUdpClientHandlers.put(clientUdp, clientHandler); } } protected void removeUdpClient(SocketServerClientHandler clientHandler) { SocketAddress clientUdp = clientHandler.socketClient.clientUdpAddress; if(clientUdp != null) { serverUdpClientHandlers.remove(clientUdp); } } /** * Executes pending tasks.
*
* WARNING: Only call this on the same thread this object was created in! Use {@link #execute(Runnable)} in case of doubt.
*/ public void listen() { listen(100); } /** * Executes pending tasks.
*
* WARNING: Only call this on the same thread this object was created in! Use {@link #execute(Runnable)} in case of doubt.
*/ public void listen(long eventTimeout) { server.selector().checkThread(); if(eventTimeout <= 10) // too small for CachedTime.nanoTime() { pyroListen(eventTimeout); handleHandshakingTimeouts(); return; } long startTime = CachedTime.nanoTime(); pyroListen(eventTimeout); long lastTime = CachedTime.nanoTime(); long timeSpend = (lastTime - startTime) / 1000000L; while(timeSpend < (eventTimeout - 10)) { pyroListen(eventTimeout - timeSpend); long newTime = CachedTime.nanoTime(); if(newTime != lastTime) { lastTime = newTime; timeSpend = (lastTime - startTime) / 1000000L; } } handleHandshakingTimeouts(); } private void pyroListen(long eventTimeout) { if(serverUdp != null) { for(long i = 1; i <= eventTimeout; i++) { try { serverUdp.listen(serverUdpNetworkBuffer); } catch(Throwable e) { if(SocketServer.IS_DEBUGGING) { SocketServer.DEBUGGING_PRINTSTREAM.println("[DEBUG] Server listen caused an exception:"); SocketServer.DEBUGGING_PRINTSTREAM.println(LowEntry.getStackTrace(e)); } } try { server.selector().select(1); } catch(Throwable e) { if(SocketServer.IS_DEBUGGING) { SocketServer.DEBUGGING_PRINTSTREAM.println("[DEBUG] Server listen caused an exception:"); SocketServer.DEBUGGING_PRINTSTREAM.println(LowEntry.getStackTrace(e)); } } } } else { for(long i = 1; i <= eventTimeout; i++) { try { server.selector().select(1); } catch(Throwable e) { if(SocketServer.IS_DEBUGGING) { SocketServer.DEBUGGING_PRINTSTREAM.println("[DEBUG] Server listen caused an exception:"); SocketServer.DEBUGGING_PRINTSTREAM.println(LowEntry.getStackTrace(e)); } } } } } /** * Takes care of clients that won't handshake. */ protected void handleHandshakingTimeouts() { long time = CachedTime.nanoTime(); if((time - lastHandshakingClientHandlerValidation) < 5000000000L) // 5 seconds { return; } lastHandshakingClientHandlerValidation = time; for(Iterator iterator = handshakingClientHandlers.iterator(); iterator.hasNext();) { SocketServerClientHandler clientHandler = iterator.next(); if((time - clientHandler.handshakingStartTime) < 15000000000L) // 15 seconds { // this is the oldest clientHandler // if this didn't timeout, the others didn't either return; } if(SocketServer.IS_DEBUGGING) { SocketServer.DEBUGGING_PRINTSTREAM.println("[DEBUG] Client was disconnected because the handshake took too long, maximum time for a handshake is 15 seconds"); } iterator.remove(); clientHandler.disconnect(); } } /** * Closes the server socket. This will only prevent new connections from being made, the existing connections will stay open. */ public void close() { if(server.selector().isNetworkThread()) { try { serverUdp.shutdown(); } catch(Throwable e) { } try { server.close(); } catch(Throwable e) { } } else { server.selector().scheduleTask(new Runnable() { @Override public void run() { try { serverUdp.shutdown(); } catch(Throwable e) { } try { server.close(); } catch(Throwable e) { } } }); } } /** * Closes the server socket. Calls {@link SocketClient#disconnect()} on every open connection. */ public void terminate() { if(server.selector().isNetworkThread()) { try { serverUdp.shutdown(); } catch(Throwable e) { } try { server.close(); } catch(Throwable e) { } for(SocketClient client : this) { client.disconnect(); } } else { server.selector().scheduleTask(new Runnable() { @Override public void run() { try { serverUdp.shutdown(); } catch(Throwable e) { } try { server.close(); } catch(Throwable e) { } for(SocketClient client : SocketServer.this) { client.disconnect(); } } }); } } /** * Closes the server socket. Calls {@link SocketClient#disconnectImmediately()} on every open connection. */ public void terminateImmediately() { if(server.selector().isNetworkThread()) { try { serverUdp.shutdown(); } catch(Throwable e) { } try { server.close(); } catch(Throwable e) { } for(SocketClient client : this) { client.disconnectImmediately(); } } else { server.selector().scheduleTask(new Runnable() { @Override public void run() { try { serverUdp.shutdown(); } catch(Throwable e) { } try { server.close(); } catch(Throwable e) { } for(SocketClient client : SocketServer.this) { client.disconnectImmediately(); } } }); } } /** * Returns an iterator to access all connected clients of this server. */ @Override public Iterator iterator() { List copy = new ArrayList(); synchronized(clients) { copy.addAll(clients); } return copy.iterator(); } /** * Performs the given action for each element of the {@code Iterable} until * all elements have been processed or the action throws an exception. * Unless otherwise specified by the implementing class, actions are * performed in the order of iteration (if an iteration order is * specified). Exceptions thrown by the action are relayed to the caller. */ public void forEachClient(Consumer action) { forEach(action); } /** * Returns the amount of connected clients. */ public int getClientCount() { synchronized(clients) { return clients.size(); } } /** * Returns the PyroNet object of this wrapper. */ public PyroServer pyro() { return server; } /** * Returns the selector. */ public PyroSelector selector() { return server.selector(); } /** * Returns the PyroNet UDP object of this wrapper. */ public PyroServerUdp pyroUdp() { return serverUdp; } /** * This function will execute the given runnable on the thread this object was created in. */ public void execute(Runnable runnable) { if(server.selector().isNetworkThread()) { runnable.run(); } else { server.selector().scheduleTask(runnable); } } /** * Returns the TCP port this server listens to. */ public int getPortTcp() { return serverPortTcp; } /** * Returns the UDP port this server listens to.
*
* Returns 0 if the server isn't listening for UDP. */ public int getPortUdp() { return serverPortUdp; } @Override public String toString() { if(serverUdp == null) { return getClass().getSimpleName() + "[" + server + "]"; } return getClass().getSimpleName() + "[" + server + ", " + serverUdp + "]"; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy