HTTP ServerSockets und Threads

sim4000

Mitglied
Hallo zusammen,

ich bin gerade dabei in Java einen kleinen und simplen Webserver zu basteln, der für ein Plugin in einem Craftbukkit Server verwendet werden soll. Das ganze ist einfach eine Spielerei um ein wenig mehr in Sachen Sockets und Threads zu lernen.

Mein Problem dabei ist nur, dass sich der ServerSocket und der Instance-Thread in der Quere kommen. Möchte ich den Server neu starten, wartet der Thread nicht bis die Socket Verbindung geschlossen ist, und rennt in eine BindException (Already in use) rein.

Den Sourcecode gibts in meinem GIT Repo: Anwendungsentwickler Gitweb - java/webserver.git/tree - src/ (Commit 120b9a0536bdead44f77e907176084a7050be455)

Dateien
  • main/SrvTest.java
    Main Programm mit kleiner CMD zum starten und stoppen.
  • ws/anwendungsentwickler/java/webserver/BasicWebserverListener.java
    Kann mit Webserver.registerListener() zur Verarbeitung eines Requests registriert werden.
  • ws/anwendungsentwickler/java/webserver/Webserver.java
    Basisklasse des Webservers. Hier wird der Thread WebserverInstance erstellt.
  • ws/anwendungsentwickler/java/webserver/WebserverInstance.java
    In der Klasse wird auf neue Anfragen gehorcht und in separaten Threads verarbeitet.
  • ws/anwendungsentwickler/java/webserver/WebserverRequestHandler.java
    Wird als Thread von WebserverInstance gestartet um die Requests zu verarbeiten.

Mein Problem ist jetzt wie gesagt, dass wenn ich ein "restart" ausführe und bei [c]WebserverInstance.stopInstance()[/c] das [c]Thread.sleep() [/c]wegnehme, nicht gewartet wird, bis der ServerSocket korrekt geschlossen wurde.

[JAVA=69]public void stopInstance() throws InterruptedException, IOException {
this.interrupt();
this.threadPool.shutdown();
try { this.threadPool.awaitTermination(10,TimeUnit.SECONDS); } catch(Exception e) { }
this.threadPool = null;

if(this.serverSocket!=null) {
this.serverSocket.setReuseAddress(true);
try { this.serverSocket.close(); } catch(Exception ex) { ex.printStackTrace(); }
this.serverSocket=null;
Thread.sleep(200); // Hack to wait for ServerSocket close
}
}[/code]

Würde mich auf Hinweise und ein bisschen Kritik zum Sourcecode allgemein sehr freuen. :)

Viele Grüße
Christian
 
Zuletzt bearbeitet:
S

SlaterB

Gast
was spricht denn gegen diese 200ms warten? für etwas derart dramitisches ist das doch nicht zuviel bezahlt,
willst du einfach nur dies wegbekommen oder was genau ist die Frage?

da du bisher eine bestimmte Methode nicht erwähnt hast kann ich mir diese Spekulationen leisten
und jetzt noch die Methode: es gibt isClosed(), schon ausprobiert?
du könntest nach dem close() oder vor neuem ServerSocket noch mit dem alten vorhandenen Objekt danach prüfen,
und solange warten bis true kommt, dann in kleineren Abständen von 20ms, falls es wirklich wichtig ist dass am Ende ein paar gespart werden

freilich ist das wohl generell zu empfehlen, falls irgendwann einmal die feste Zeit von 200ms oder sonstigen X
doch überschritten wird und es Exceptions bei neuem ServerSocket gibt
 

sim4000

Mitglied
Hi,

die Entwickler in meinem Bekanntenkreis sagten zu mir immer, dass man, wenn es geht, auf Thread.sleep verzichten sollte. An die Erklärung dazu kann ich mich allerdings nicht mehr erinnern. Deswegen bin ich davon ausgegangen das es vielleicht einen eleganteren Weg gibt.

Den Weg mit [c]isClosed()[/c] habe ich auch schon versucht.
Allerdings scheint man sich da nicht so wirklich drauf verlassen zu können.

Java:
	static public boolean waitSocketClose(ServerSocket socket) {
		System.out.println("server local port: "+socket.getLocalPort()+" isclosed: "+socket.isClosed()+" bound: "+socket.isBound());
		
		int waitsecounds = 20;
		int sleeptime = 20;
		int maxwait = (waitsecounds*1000)/sleeptime;
		int i=0;
		
		try {
			//Thread.sleep(200);
			while(socket.isClosed()==false) {
				if(i<maxwait) {
					i++;
					Thread.sleep(sleeptime);
				} else {
					return false;
				}
			}
		} catch(Exception e) {
			return false;
		}
		
		System.out.println("server "+(i*20)+" millis waited ");
		
		return true;
	}

Java:
	public void stopInstance() throws InterruptedException, IOException {
		this.interrupt();
		this.threadPool.shutdown();
		try { this.threadPool.awaitTermination(10,TimeUnit.SECONDS); } catch(Exception e) { }
		
		if(this.serverSocket!=null) {
			try { this.serverSocket.close(); } catch(Exception ex) { ex.printStackTrace(); }
			
			FiaeUtils.waitSocketClose(this.serverSocket);
			
		}
	}

Dieses Schnipsel hatte ich mir zum testen mal gebastelt. Wenn ich das [c]Thread.sleep(200);[/c] auskommentiere, kommt es zu einer BindException, wenn ich den restart der Verbindung zu schnell hintereinander Ausführe. Lasse ich das [c]Thread.sleep(200);[/c] drin, wird die while mit [c]isClosed()[/c] nicht benötigt.

Wenn man sich die Konsolenausgaben mal anschaut, sieht man auch, dass [c]isClosed()[/c] immer auf true steht, wenn die Methode aufgerufen wird.

Code:
websrv> start
Start Server
websrv> restart
Restart Server
server local port: 8080 isclosed: true bound: true
0 millis waited server
websrv> restart
Restart Server
server local port: 8080 isclosed: true bound: true
0 millis waited server


System exited.
java.net.BindException: Address already in use

Ich schätze mal das hier das TIME_WAIT nicht berücksichtigt wird und das Flag für [c]isClosed()[/c] einfach beim Aufruf von [c]close()[/c] auf true gesetzt wird. Nur welchen Sinn dieses Flag dann haben sollte ist mir schleierhaft. Man kann sich ja auf keines der is-Methoden so wirklich verlassen, wenn es um das Schließen der Verbindung geht...
 
S

SlaterB

Gast
nun gut, zumindest eine Info, besser als wäre es komplett unerwähnt geblieben ;)

gleich noch eine Spekulation, da es mir an deinen Ausgaben gerade auffällt:
was macht eigentlich isBound(), geht das nach 200ms oder irgendwann auf false?
wäre dann ja ein gute Warte-Bedingung,
while(socket.isBound()) {

denn
public boolean isBound()

Returns the binding state of the ServerSocket.

Returns:
true if the ServerSocket succesfuly bound to an address
klingt ja irgendwie verdächtlich relevant zu
java.net.BindException: Address already in use

vielleicht bleibt aber auch Bound ewig bestehen, wenn allein die Information des Ports irgendwann mal abgelegt wurde


-------

> Ich schätze mal dass [..] das Flag für isClosed() einfach beim Aufruf von close() auf true gesetzt wird.

stimmt, hier der Quellcode, und Bound sieht dort auch nicht viel besser aus leider

Java:
    public void close() throws IOException {
	synchronized(closeLock) {
	    if (isClosed())
		return;
	    if (created)
		impl.close();
	    closed = true;
	}
    }
 
Zuletzt bearbeitet von einem Moderator:

sim4000

Mitglied
Bei der Idee mit dem [c]isBound()[/c] dachte ich eben "geil, dass könnte echt gehen!", dann hatte ich folgende Ausgabe:
Code:
websrv> restart
Restart Server
server local port: 8080 isclosed: true bound: true
server afterts200 local port: 8080 isclosed: true bound: true
0 millis waited server
Der zweiter Test von [c]isBound()[/c] wird nach der while in meiner Helper Methode ausgeführt. Sprich wieder so ein Pseudo-Flag was nur beim Verbinden hilft... Kann doch echt nicht wahr sein, dass es keine Möglichkeit gibt.

Letzte Lösungsidee von mir wäre jetzt noch das [c]new ServerSocket()[/c] in einer Schleife zu versuchen und wenn das nach 5 Sekunden nicht geklappt hat die Exception "durchlassen".
 

sim4000

Mitglied
So, ich habe meinen nächsten Versuch es stabil zu bekommen fertig.

Java:
// Try to bind to hostport
int waitsecounds = 5;
int sleeptime = 20;
int maxwait = (waitsecounds * 1000) / sleeptime;
int i = 0;

try {
   while (true) {
       try {
           // bind
           this.serverSocket = new ServerSocket(bindport, 0, bindhost);
           break;
       } catch (IOException e) {
           Thread.sleep(sleeptime);
           if (i >= maxwait) {
               throw e;
           }
       }
       i++;
   }
} catch (InterruptedException e) {
   throw new IOException("Could not bind to hostport");
}

this.serverSocket.setSoTimeout(200);
this.serverSocket.setReuseAddress(true);

Das granze Projekt im Git: Anwendungsentwickler Gitweb - java/webserver.git/tree (Tag 0.1beta)
Snapshot Download: http://gitweb.fiae.ws/java/webserver.git/snapshot/2846334a1c6f0b48e489df9eb7fe06f56e7e5a21.tar.gz (Tag 0.1beta)

Bessere Ideen gerne willkommen.

Vielen Dank an SlaterB für die Denkanstöße. :)

Würde mich freuen wenn sich hier noch jemand finden würde der den Sourcecode mal testet.
Eine while(true) mit curl hat der Server schon ohne Probleme überstanden. Selbst beim start, stop und restart. :)

Viele Grüße
Christian
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Z Verbindung zwischen 2 Rechnern über ServerSockets nicht möglich Netzwerkprogrammierung 3
2 Schliessen eines Serversockets Netzwerkprogrammierung 2
S Problem mit 2 Serversockets unter Win XP Netzwerkprogrammierung 7
T TCP mit und ohne Threads Netzwerkprogrammierung 1
Yonnig Threads mit Client/Server und GUI (laufend bis button-click) Netzwerkprogrammierung 9
K Threads/Server/telnet Fehler Netzwerkprogrammierung 2
D Exception Handling bei In/Outputsockets in eigenen Threads Netzwerkprogrammierung 1
C Frage zu Threads & Server Netzwerkprogrammierung 4
K Threads closen und Sockets schliessen Netzwerkprogrammierung 5
J Threads & Streams Netzwerkprogrammierung 9
P RMI Threads die über RMI auf Datenbank zugreifen Netzwerkprogrammierung 2
B Sockets, Threads & Plugins Netzwerkprogrammierung 7
T Verbindungsversuche über TCP Sockets von mehreren Threads führt zu Serverabsturz Netzwerkprogrammierung 2
R Threads mit einem WebService Netzwerkprogrammierung 4
M Verständnisfrage zu RMI und Threads Netzwerkprogrammierung 2
L einfacher server ohne threads Netzwerkprogrammierung 4
A Threads auflisten und nacheinander ansprechen Netzwerkprogrammierung 6
C I/O - Synchronisation durch Threads in einem ChatClient Netzwerkprogrammierung 4
J Probleme mit Threads (Client terminiert) Netzwerkprogrammierung 4
P Threads einbinden Netzwerkprogrammierung 11
P RMI Callback (mit Threads?) Netzwerkprogrammierung 3
T RMI Threads und Synchronized Netzwerkprogrammierung 13
A Datenverteilung: Mehrere Threads verwenden? Netzwerkprogrammierung 4
S Threads beim Server koordinieren Netzwerkprogrammierung 5
L ClientServer mit 2 Threads Netzwerkprogrammierung 5
N Threads und Socketprogrammierung Netzwerkprogrammierung 4
G 1 Socket 2 Threads problem Netzwerkprogrammierung 13
K Problem mit Threads Netzwerkprogrammierung 3
S Threads bei Web Service sinnvoll oder Alternative? Netzwerkprogrammierung 2
K Hintergrund - Threads Netzwerkprogrammierung 3
G Socket Programmierung - Max. Threads Netzwerkprogrammierung 5
C NetScanner arbeitet trotz Threads langsam Netzwerkprogrammierung 6
L UDP-Server mit Threads Netzwerkprogrammierung 8
K Windows 10 Threads gleichzeitig Netzwerkprogrammierung 18
C Join von Threads bei I/O-Operation Netzwerkprogrammierung 6
F Threads synchronisieren mit Pipes Netzwerkprogrammierung 3
G benötige Beispiel für parallel ablaufende Threads Netzwerkprogrammierung 3
F Problem mit Threads und Sockets Netzwerkprogrammierung 3
TRunKX Threads beenden sich selber? Netzwerkprogrammierung 6
T Kleiner Chatserver: Threads oder Multiplex? Netzwerkprogrammierung 18

Ähnliche Java Themen

Neue Themen


Oben