forked from IF-LK-2020/wordle
359 lines
11 KiB
Java
359 lines
11 KiB
Java
/**
|
|
* <p>
|
|
* Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2018
|
|
* </p>
|
|
* <p>
|
|
* Klasse Server
|
|
* </p>
|
|
* <p>
|
|
* Objekte von Unterklassen der abstrakten Klasse Server ermoeglichen das
|
|
* Anbieten von Serverdiensten, so dass Clients Verbindungen zum Server mittels
|
|
* TCP/IP-Protokoll aufbauen koennen. Zur Vereinfachung finden Nachrichtenversand
|
|
* und -empfang zeilenweise statt, d. h., beim Senden einer Zeichenkette wird ein
|
|
* Zeilentrenner ergaenzt und beim Empfang wird dieser entfernt.
|
|
* Verbindungsannahme, Nachrichtenempfang und Verbindungsende geschehen
|
|
* nebenlaeufig. Auf diese Ereignisse muss durch Ueberschreiben der entsprechenden
|
|
* Ereignisbehandlungsmethoden reagiert werden. Es findet nur eine rudimentaere
|
|
* Fehlerbehandlung statt, so dass z.B. Verbindungsabbrueche nicht zu einem
|
|
* Programmabbruch fuehren. Einmal unterbrochene oder getrennte Verbindungen
|
|
* koennen nicht reaktiviert werden.
|
|
* </p>
|
|
*
|
|
* @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule
|
|
* @version 30.08.2016
|
|
*/
|
|
import java.net.*;
|
|
import java.io.*;
|
|
|
|
public abstract class Server
|
|
{
|
|
private NewConnectionHandler connectionHandler;
|
|
private List<ClientMessageHandler> messageHandlers;
|
|
|
|
private class NewConnectionHandler extends Thread
|
|
{
|
|
private ServerSocket serverSocket;
|
|
private boolean active;
|
|
|
|
public NewConnectionHandler(int pPort)
|
|
{
|
|
try
|
|
{
|
|
serverSocket = new ServerSocket(pPort);
|
|
start();
|
|
active = true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
serverSocket = null;
|
|
active = false;
|
|
}
|
|
}
|
|
|
|
public void run()
|
|
{
|
|
while (active)
|
|
{
|
|
try
|
|
{
|
|
//Warten auf Verbdinungsversuch durch Client:
|
|
Socket clientSocket = serverSocket.accept();
|
|
// Eingehende Nachrichten vom neu verbundenen Client werden
|
|
// in einem eigenen Thread empfangen:
|
|
addNewClientMessageHandler(clientSocket);
|
|
processNewConnection(clientSocket.getInetAddress().getHostAddress(),clientSocket.getPort());
|
|
}
|
|
|
|
catch (IOException e)
|
|
{
|
|
/*
|
|
* Kann keine Verbindung zum anfragenden Client aufgebaut werden,
|
|
* geschieht nichts.
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
public void close()
|
|
{
|
|
active = false;
|
|
if(serverSocket != null)
|
|
try
|
|
{
|
|
serverSocket.close();
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
/*
|
|
* Befindet sich der ServerSocket im accept()-Wartezustand oder wurde
|
|
* er bereits geschlossen, geschieht nichts.
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
private class ClientMessageHandler extends Thread
|
|
{
|
|
private ClientSocketWrapper socketWrapper;
|
|
private boolean active;
|
|
|
|
private class ClientSocketWrapper
|
|
{
|
|
private Socket clientSocket;
|
|
private BufferedReader fromClient;
|
|
private PrintWriter toClient;
|
|
|
|
public ClientSocketWrapper(Socket pSocket)
|
|
{
|
|
try
|
|
{
|
|
clientSocket = pSocket;
|
|
toClient = new PrintWriter(clientSocket.getOutputStream(), true);
|
|
fromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
clientSocket = null;
|
|
toClient = null;
|
|
fromClient = null;
|
|
}
|
|
}
|
|
|
|
public String receive()
|
|
{
|
|
if(fromClient != null)
|
|
try
|
|
{
|
|
return fromClient.readLine();
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
}
|
|
return(null);
|
|
}
|
|
|
|
public void send(String pMessage)
|
|
{
|
|
if(toClient != null)
|
|
{
|
|
toClient.println(pMessage);
|
|
}
|
|
}
|
|
|
|
public String getClientIP()
|
|
{
|
|
if(clientSocket != null)
|
|
return(clientSocket.getInetAddress().getHostAddress());
|
|
else
|
|
return(null); //Gemaess Java-API Rueckgabe bei nicht-verbundenen Sockets
|
|
}
|
|
|
|
public int getClientPort()
|
|
{
|
|
if(clientSocket != null)
|
|
return(clientSocket.getPort());
|
|
else
|
|
return(0); //Gemaess Java-API Rueckgabe bei nicht-verbundenen Sockets
|
|
}
|
|
|
|
public void close()
|
|
{
|
|
if(clientSocket != null)
|
|
try
|
|
{
|
|
clientSocket.close();
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
/*
|
|
* Falls eine Verbindung getrennt werden soll, deren Endpunkt
|
|
* nicht mehr existiert bzw. ihrerseits bereits beendet worden ist,
|
|
* geschieht nichts.
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
private ClientMessageHandler(Socket pClientSocket)
|
|
{
|
|
socketWrapper = new ClientSocketWrapper(pClientSocket);
|
|
if(pClientSocket!=null)
|
|
{
|
|
start();
|
|
active = true;
|
|
}
|
|
else
|
|
{
|
|
active = false;
|
|
}
|
|
}
|
|
|
|
public void run()
|
|
{
|
|
String message = null;
|
|
while (active)
|
|
{
|
|
message = socketWrapper.receive();
|
|
if (message != null)
|
|
processMessage(socketWrapper.getClientIP(), socketWrapper.getClientPort(), message);
|
|
else
|
|
{
|
|
ClientMessageHandler aMessageHandler = findClientMessageHandler(socketWrapper.getClientIP(), socketWrapper.getClientPort());
|
|
if (aMessageHandler != null)
|
|
{
|
|
aMessageHandler.close();
|
|
removeClientMessageHandler(aMessageHandler);
|
|
processClosingConnection(socketWrapper.getClientIP(), socketWrapper.getClientPort());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void send(String pMessage)
|
|
{
|
|
if(active)
|
|
socketWrapper.send(pMessage);
|
|
}
|
|
|
|
public void close()
|
|
{
|
|
if(active)
|
|
{
|
|
active=false;
|
|
socketWrapper.close();
|
|
}
|
|
}
|
|
|
|
public String getClientIP()
|
|
{
|
|
return(socketWrapper.getClientIP());
|
|
}
|
|
|
|
public int getClientPort()
|
|
{
|
|
return(socketWrapper.getClientPort());
|
|
}
|
|
|
|
}
|
|
|
|
public Server(int pPort)
|
|
{
|
|
connectionHandler = new NewConnectionHandler(pPort);
|
|
messageHandlers = new List<ClientMessageHandler>();
|
|
}
|
|
|
|
public boolean isOpen()
|
|
{
|
|
return(connectionHandler.active);
|
|
}
|
|
|
|
public boolean isConnectedTo(String pClientIP, int pClientPort)
|
|
{
|
|
ClientMessageHandler aMessageHandler = findClientMessageHandler(pClientIP, pClientPort);
|
|
if (aMessageHandler != null)
|
|
return(aMessageHandler.active);
|
|
else
|
|
return(false);
|
|
}
|
|
|
|
public void send(String pClientIP, int pClientPort, String pMessage)
|
|
{
|
|
ClientMessageHandler aMessageHandler = this.findClientMessageHandler(pClientIP, pClientPort);
|
|
if (aMessageHandler != null)
|
|
aMessageHandler.send(pMessage);
|
|
}
|
|
|
|
public void sendToAll(String pMessage)
|
|
{
|
|
synchronized(messageHandlers)
|
|
{
|
|
messageHandlers.toFirst();
|
|
while (messageHandlers.hasAccess())
|
|
{
|
|
messageHandlers.getContent().send(pMessage);
|
|
messageHandlers.next();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void closeConnection(String pClientIP, int pClientPort)
|
|
{
|
|
ClientMessageHandler aMessageHandler = findClientMessageHandler(pClientIP, pClientPort);
|
|
if (aMessageHandler != null)
|
|
{
|
|
processClosingConnection(pClientIP, pClientPort);
|
|
aMessageHandler.close();
|
|
removeClientMessageHandler(aMessageHandler);
|
|
}
|
|
|
|
}
|
|
|
|
public void close()
|
|
{
|
|
connectionHandler.close();
|
|
|
|
synchronized(messageHandlers)
|
|
{
|
|
ClientMessageHandler aMessageHandler;
|
|
messageHandlers.toFirst();
|
|
while (messageHandlers.hasAccess())
|
|
{
|
|
aMessageHandler = messageHandlers.getContent();
|
|
processClosingConnection(aMessageHandler.getClientIP(), aMessageHandler.getClientPort());
|
|
aMessageHandler.close();
|
|
messageHandlers.remove();
|
|
}
|
|
}
|
|
|
|
}
|
|
public abstract void processNewConnection(String pClientIP, int pClientPort);
|
|
|
|
public abstract void processMessage(String pClientIP, int pClientPort, String pMessage);
|
|
|
|
public abstract void processClosingConnection(String pClientIP, int pClientPort);
|
|
|
|
private void addNewClientMessageHandler(Socket pClientSocket)
|
|
{
|
|
synchronized(messageHandlers)
|
|
{
|
|
messageHandlers.append(new Server.ClientMessageHandler(pClientSocket));
|
|
}
|
|
}
|
|
|
|
private void removeClientMessageHandler(ClientMessageHandler pClientMessageHandler)
|
|
{
|
|
synchronized(messageHandlers)
|
|
{
|
|
messageHandlers.toFirst();
|
|
while (messageHandlers.hasAccess())
|
|
{
|
|
if (pClientMessageHandler == messageHandlers.getContent())
|
|
{
|
|
messageHandlers.remove();
|
|
return;
|
|
}
|
|
else
|
|
messageHandlers.next();
|
|
}
|
|
}
|
|
}
|
|
|
|
private ClientMessageHandler findClientMessageHandler(String pClientIP, int pClientPort)
|
|
{
|
|
synchronized(messageHandlers)
|
|
{
|
|
ClientMessageHandler aMessageHandler;
|
|
messageHandlers.toFirst();
|
|
|
|
while (messageHandlers.hasAccess())
|
|
{
|
|
aMessageHandler = messageHandlers.getContent();
|
|
if (aMessageHandler.getClientIP().equals(pClientIP) && aMessageHandler.getClientPort() == pClientPort)
|
|
return (aMessageHandler);
|
|
messageHandlers.next();
|
|
}
|
|
return (null);
|
|
}
|
|
}
|
|
|
|
} |