# Server sauber beenden



## musiKk (4. Jun 2008)

Guten Tag,

ich arbeite gerade an einem Programm, welches quasi als Server laeuft und ueber Netzwerk-Sockets angesprochen werden soll. Dazu habe ich einen Thread mit einem ServerSocket, der auf eingehende Verbindungen wartet. Kommt eine, wird eine Connection geoeffnet und ueber die kann man dann kommunizieren.

Nun moechte ich aber auch die Moeglichkeit haben, dass die komplette Anwendung auch ueber diesen Socket beendet werden kann. Sauber natuerlich. Allerdings weiss ich nicht so ganz, wie ich das am schlauesten anstellen soll. Im Moment sieht es so aus, dass der Server der Connection sich selbst mitgibt und die Moeglichkeit bietet, den ServerSocket zu schliessen. Da der Server allerdings derweil schon wieder an selbigem auf die naechste Verbindung wartet, wird hier eine Exception geworfen... damit wuerde ich praktisch Exceptions zur "Flow Control" missbrauchen, was ich gar nicht schoen finde.

Ganz grob skizziert ists grad so:

main:

```
Server server = new Server();
server.start();
```

Server:

```
public class Server extends Thread {
	
	private ServerSocket serverSocket;
	
	@Override
	public synchronized void run() {
		
		try {
			serverSocket = new ServerSocket(31337);
			while(true) {
				System.out.println("accepting");
				Socket socket = serverSocket.accept();
				
				System.out.println("new connection");
				Thread connection = new Connection(socket, this);
				connection.start();

				System.out.println("started");
			}
		} catch (IOException e) {
			System.err.println("server exiting\n");
//			ja nu is der Server halt beendet, aber toll ist das ja nicht
			return;
		}
		
	}
	
	public ServerSocket getServerSocket() {
		return serverSocket;
	}

}
```

Connection:

```
public class Connection extends Thread {
	
	private Socket socket;
	private BufferedReader in = null;
	private BufferedWriter out = null;
	private Server server;
	
	public Connection(Socket socket, Server server) {
		this.socket = socket;
		this.server = server;
	}
	
	@Override
	public synchronized void run() {
		try {
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			
			boolean continueThread = true;
			
			while(continueThread) {
				out.write("prompt: ");
				out.flush();
				String line = in.readLine();
				System.out.println(socket.getPort() + " " + line);
				
				if(line.equals("exit")) {
					continueThread = false;
				} else {
					continueThread = parseLine(line);
					}
				if(!continueThread) {
					in.close();
					out.close();
					socket.close();
					break;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private boolean parseLine(String line) {
		try {
			if(line.equals("shutdown")) {
				out.write("shutting down...\n");
				out.flush();
				server.getServerSocket().close(); // hier wird der Server getoetet...
				return false;
			}
		} catch (SchedulerException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return true;
	}

}
```

Vielleicht hat da jemand einen besseren Ratschlag fuer mich. :/


----------



## Kim Stebel (4. Jun 2008)

So lange es die Lesbarkeit des Programms nicht behindert, spricht doch gar nichts dagegen. Solche Regeln wie "Exception für flow control ist böse" gelten ja nicht immer uneingeschränkt. So lange du da nen Kommentar dran machst kann man das gut lesen.
Außerdem verstehe ich auch die API-docs so als sei das die übliche Vorgehensweise.
Was durch diese Regel verboten werden soll ist ja eher so ein Unsinn wie:

```
int[] ia=new int[1000];
        try
        {
          for (int i=0;;i++)
          {
            ia[i]=i;
          }
        } catch (ArrayIndexOutOfBoundsException e){}
```


----------



## FArt (4. Jun 2008)

Tipp: im Fall von Fehlern werden deine Streams nicht geschlossen. Gerde bei einem Server, der ein bestimmtes Fehler-Verhalten aufweisen sollte, kann das sehr unangenehm werden.

Wenn eine Excepiton als FlowControl herhalten muss, dann sollte das eine spezielle Exception sein, die entsprechend dokumentiert ist und nur zu diesem Zweck verwendet wird. Allles andere sollte als Fehler behandelt werden (jetzt kommt dann das Fehler-Verhalten wieder ins Spiel)


----------



## Kim Stebel (4. Jun 2008)

FArt: Der sourcecode war doch nur als Skizze gedacht, wenn ich das richtig verstanden habe...abgesehen davon geht es bei dieser API gar nicht anders. Warum das nicht über nen Rückgabewert von accept gelöst wird ist mir schleierhaft.


----------



## musiKk (4. Jun 2008)

Nagut, dass eine Exception geworfen wird, kann ich schon nachvollziehen. Der Server horcht halt und auf einmal wird ihm der Socket geschlossen.

Ich werds also wohl erstmal so lassen, wies ist.



			
				FArt hat gesagt.:
			
		

> Tipp: im Fall von Fehlern werden deine Streams nicht geschlossen. Gerde bei einem Server, der ein bestimmtes Fehler-Verhalten aufweisen sollte, kann das sehr unangenehm werden.



Das kann ich allerdings nicht ganz nachvollziehen, ich schliesse doch alle Streams?


----------



## Kim Stebel (4. Jun 2008)

musiKk: Wenn in dem try-Block eine Exception geworfen wird, werden die streams nicht geschlossen. Das gehört in den finally-Abschnitt.


----------



## musiKk (4. Jun 2008)

Achso, stimmt. Ich hatte mich im Moment nur auf den Server konzentriert und die Connection nicht so beachtet. Aber Danke fuer den Hinweis, das werde ich aendern.


----------

