NIO:channel.close() auf Client scheinbar vom Server ignorier

Status
Nicht offen für weitere Antworten.
L

LarsbrauchtHilfe

Gast
Ich versuche im Rahmen eines Hochschul Softwareprojekts mit NewIO die Basis für einen performaten TCP/IP Server zu legen, auf dessen Basis ein Spiel entstehen soll. Auf der Server Seite kommen dazu Channel, Selector und Keys zum Einsatz.

Im Prinzip funktioniert das ganze schon, und der Client kann eine kurze Nachricht in die "Leitung" stecken die der Server dann einfach per Systt.out.writln ausgibt. Wenn der Client allerdings beendet oder den Channel schließt, wird der Key beim Server nicht deregistriert, der Status des Channels scheint unverändert (isOpen gibt true zurück). Ich würde aber erwarten das der Server den Channel schließt und damit die Resourcen wieder freigibt. Hab ich da was falsch verstanden?

Wird der Channel im Client erst in der Methode connect definiert, bekommt der Server interssanterweise eine IOException sobald der Scope verlassen wird, womit er dann selber die Verbindung beenden kann. Das ist aber normalerweise ja nicht der Fall.

Hab als Basis für meine Entwicklung einen HTTP Server Modell genommen, dort wird nach jeder Anfrage die Verbindung vom Server eh beendet. Bei meinem Server soll die TCP verbindung allerdings aufrechterhalten werden. Möglicherweise liegt darin letztlich das Problem...

Hier der Code für den Client:

Code:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

public class Client {
	private SocketChannel channel;
	private Charset asciiCharset;
	private CharsetDecoder asciiCharsetDecoder;
	private CharsetEncoder asciiCharsetEncoder;
	private ByteBuffer readBuffer;
	
	public Client() {
	    // Für die ByteBuffer <-> String Umwandlung
	    asciiCharset = Charset.forName("US-ASCII");
	    asciiCharsetDecoder = asciiCharset.newDecoder();
	    asciiCharsetEncoder = asciiCharset.newEncoder();
	}
	
	public boolean connect(String address, int port) {
		try {
			channel = SocketChannel.open(new InetSocketAddress(address,port));
	} catch (UnknownHostException e) {
		e.printStackTrace();
		return false;
	} catch (IOException e){
		e.printStackTrace();
		return false;
	} 
		return true;
	}
	
	public boolean login(String username, String password) {
		try {
			channel.write(asciiCharset.encode("Hello World\r\n"));
			System.out.println("Wrote to channel :-)");
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public void close() {
		if(null!=channel) {
			try {
				channel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	public static void main (String[] args) {
		String host = "127.0.0.1";
		int port = 8000;
		
		Client client = new Client();
		if(client.connect(host,port)) {
			System.out.println("Connection to "+host+":"+port+" established.");
			client.login("lars","meinpw");
			client.close();
		}
	}
}

Und Code für den Server, acceptConnectionThread und LoginManagerThread im Anschluss

Code:
import java.nio.channels.Selector;

public class Server {
	  private static final int HTTPD_PORT = 8000;


	  private AcceptConnectionsThread acceptConnectionsThread;
	  private LoginManagerThread loginManagerThread;

	  public static void main(String[] args) {
	    int port = HTTPD_PORT;

	    try {
	      Server s = new Server(port);
	      s.start();
	    } catch(Exception ex) {
	      System.err.println(ex);
	    }
	  }

	  public Server(int port) throws Exception {
	    Selector acceptSelector = Selector.open();
	    Selector readSelector = Selector.open();
	    
	    ConnectionList connections = new ConnectionList(readSelector);
	    acceptConnectionsThread = new AcceptConnectionsThread(acceptSelector, connections, port);
	    loginManagerThread = new LoginManagerThread(readSelector, connections);
	  }

	  public void start() {
	    acceptConnectionsThread.start();
	    loginManagerThread.start();
	  }
	}



Der AcceptConnectionsThread

Code:
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;



class AcceptConnectionsThread extends Thread {
	  private ServerSocketChannel ssc;
	  private Selector connectSelector;
	  private ConnectionList acceptedConnections;

	  public AcceptConnectionsThread(Selector connectSelector, ConnectionList list, int port) throws Exception {
	    super("AcceptConnections");

	    this.connectSelector = connectSelector;
	    this.acceptedConnections = list;

	    ssc = ServerSocketChannel.open();
	    ssc.configureBlocking(false);

	    InetSocketAddress address = new InetSocketAddress(port);
	    ssc.socket().bind(address);

      System.out.println("Bound to " + address);

	    ssc.register(this.connectSelector, SelectionKey.OP_ACCEPT);
	  }
	   
	  public void run() {
	    while(true) {
	      try {
	        //if(Server.verbose) 
	          System.out.println("AcceptThread: Selecting");

	        connectSelector.select();

	        acceptPendingConnections();
	      } catch(Exception ex) {
	        ex.printStackTrace();
	      }
	    }
	  }

	  protected void acceptPendingConnections() throws Exception {
	    Set readyKeys = connectSelector.selectedKeys();

	    for(Iterator i = readyKeys.iterator(); i.hasNext(); ) {
	      SelectionKey key = (SelectionKey)i.next();
	      i.remove();

	      ServerSocketChannel readyChannel = (ServerSocketChannel)key.channel();

	      SocketChannel incomingChannel = readyChannel.accept();

	        System.out.println("AcceptThread: Connection from " + incomingChannel.socket().getInetAddress() +":"+ incomingChannel.socket().getPort());

	      acceptedConnections.push(incomingChannel);
	    }
	  }
	}

Der LoginManagerThread, hier wird der Channel ausgelesen


Code:
import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set;



class LoginManagerThread extends Thread {
	private static final int READ_BUFFER_SIZE = 16;  
	
	private ServerSocketChannel ssc;
	private Selector readSelector;
	private ConnectionList acceptedConnections;
	private Charset asciiCharset;
	private CharsetDecoder asciiCharsetDecoder;
	private ByteBuffer readBuffer;
	  
	  public LoginManagerThread(Selector readSelector, ConnectionList acceptedConnections) throws Exception {
	    super("LoginManager");

	    this.readSelector = readSelector;
	    this.acceptedConnections = acceptedConnections;

	    // hier werden Teile des Requests reingelesen
	    this.readBuffer = ByteBuffer.allocateDirect(READ_BUFFER_SIZE);
	    
	    // Für die ByteBuffer <-> String Umwandlung
	    asciiCharset = Charset.forName("US-ASCII");
	    asciiCharsetDecoder = asciiCharset.newDecoder();
	    //responseBuffers[0] = initializeResponseHeader();


	  }
	   
	  public void run() {
	    while(true) {
	        try {
      
	          registerNewChannels();
	      
	          int keysReady = readSelector.select();
	          //System.out.println("ready keys: "+Integer.toString(keysReady));
	          if(keysReady > 0) {
	            acceptPendingRequests();
	          }
	        } catch(Exception ex) {
	          ex.printStackTrace();
	        }
	        
	      // slow down server  (zum debuggen)
	    try {
	        sleep(500); 
	    } catch (Exception e) {
	    	e.printStackTrace();
	    	
	    }
	      }
	  }

	  protected void registerNewChannels() throws Exception {
	    SocketChannel channel;
	    while(null != (channel = acceptedConnections.removeFirst())) {
	    	System.out.println("Register Channel to read from: "+channel.socket().getPort());
	    	channel.configureBlocking(false);
	      channel.register(readSelector, SelectionKey.OP_READ, new StringBuffer());
	    }  
	  }
	  
	  protected void acceptPendingRequests() throws Exception {
	    Set readyKeys = readSelector.selectedKeys();
	    
	    
	    for(Iterator i = readyKeys.iterator(); i.hasNext(); ) {
	    	//System.out.println("Channel ready for read");
	    SelectionKey key = (SelectionKey)i.next();
	      i.remove();
	      //System.out.println("isopen: "+key.channel().isOpen());
	      readRequest(key);
	    }
	  }
	  
	  protected void readRequest(SelectionKey key) throws Exception {
	    SocketChannel incomingChannel = (SocketChannel)key.channel();
	    Socket incomingSocket = incomingChannel.socket();
	    
	    try {
	      int bytesRead = incomingChannel.read(readBuffer);
	      readBuffer.flip();
	      String result = asciiCharsetDecoder.decode(readBuffer).toString();
	      readBuffer.clear();
	      System.out.println("Empfange: "+result);
	      
	      StringBuffer requestString = (StringBuffer)key.attachment();
	      
	      requestString.append(result);
	      
	      if(result.endsWith("\n\n") || result.endsWith("\r\n\r\n")) {
	          handleCompletedRequest(requestString.toString(), incomingChannel);
	      }
	    } 
	    // Brauch ich die RequestException aus dem Server Beispiel?
	    /*catch(RequestException re) {
	      sendError(incomingChannel, re);
	    } */catch(IOException ioe) {
	    	//ioe.printStackTrace();
	    	// close channel!
	    	incomingChannel.close();
	    	System.out.println("Achtung: IOException! Wahrscheinlich weil remote host die verbindung beendet hat. Channel wird geschlossen und damit keys deregistriert!");
	    	//sendError(incomingChannel, RequestException.INTERNAL_SERVER_ERROR);
	    }
	  }
	    
	    protected void handleCompletedRequest(String request, SocketChannel channel) throws 


/*RequestException,*/ IOException {
	        /*StringTokenizer tok = new StringTokenizer(request);
	        tok.nextToken();                       // skip the method
	        String path = tok.nextToken();         // grab the URI, ignore the rest

	        sendFile(path, channel);
	        
	        Server.statistics.request();
	        
	        // This behaves like HTTP 1.0, close connection
	        // after handling the request.
	        channel.close();*/
	    	// Gib mal komplette erhaltene Nachricht aus
	    	System.out.println("Komplette Nachricht von:");
	      }
	  }
 
L

LarsbrauchtHilfe

Gast
Hm, die Server Beispiele schließen die Verbindung immer selbst nach dem RequestHAndling. Mein Server macht das aber nicht, weil die Verbindung bestehen bleiben soll. Vielleicht ist die Frage also: Wie bekommt der server den disconnect des clients mit? einfach ein timout für den channel oder gar auf applications ebene (kein input für user) setzen?
 

semi

Top Contributor
Was sagt eigentlich channel.isConnected()?
Ansonsten kriegst Du auch eine ClosedChannelException, wenn Du versuchst auf eine
von der Gegenstelle unterbrochene Verbindung zuzugreifen.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
E FTP FTPS Server gibt Fehlernachricht "522 SSL/TLS required on the data channel" zurück Netzwerkprogrammierung 1
O Java Secure Channel Netzwerkprogrammierung 2
T Socket sendet erst nach socket.close() Netzwerkprogrammierung 2
S Socket schließen mit .close() Netzwerkprogrammierung 4
N Client bekommt close vom Server nicht mit Netzwerkprogrammierung 3
J close() Socket Verbindung nötig ? Netzwerkprogrammierung 3
G Socket close Netzwerkprogrammierung 14
J socket.close() Problem ----- java.net.BindException Netzwerkprogrammierung 4
C ObjectOutputStream + Socket close Netzwerkprogrammierung 6
hieuhp132 Server wird nicht auf zweiten Anfrage von Client geupdated Netzwerkprogrammierung 3
I Performanteste Kommunikationsmethode zwischen Client u. Server Netzwerkprogrammierung 4
L Socket Automatische Zuweisung von Server und Client Rolle Netzwerkprogrammierung 12
ExceptionOfExpectation Server/Client-Kommunikation Netzwerkprogrammierung 34
M Server-Client-System für Browsergame Netzwerkprogrammierung 5
B Axis2 Webservice mit Client Zertifikat Authentifizierung Netzwerkprogrammierung 3
Yonnig Threads mit Client/Server und GUI (laufend bis button-click) Netzwerkprogrammierung 9
T Jetty mit Client-Zertifikat nur bei spezifischer URL Netzwerkprogrammierung 1
J Einlesen von Servernachrichten von TCP-Client Netzwerkprogrammierung 17
J Client-Server und SOAP Netzwerkprogrammierung 23
L30nS RMI Aufruf einer Client-Methode von einem RMI-Server Netzwerkprogrammierung 3
T String von Client zu Server kommt nicht an Netzwerkprogrammierung 92
D WebSocket Server mit HTML Client und Java Server Netzwerkprogrammierung 5
D Server - Client Informationsaustausch, Möglichkeiten Netzwerkprogrammierung 3
H Socket Chat entwickeln mit Java Server Client Netzwerkprogrammierung 4
X Kann ich einen Client/Server verbindung hinkriegen die mir alle paar Sekunden die aktuellen Daten per Realtime zuschickt ? Netzwerkprogrammierung 9
T Client zu Client Kommunikation Netzwerkprogrammierung 2
D Slf4j - Logging - Client-Server Architektur Netzwerkprogrammierung 3
J client server mit nur einem PC Netzwerkprogrammierung 33
M Socket Nachricht von TCP-Client an Server schicken Netzwerkprogrammierung 12
M Socket Verbindung Matlab(Server) Java(Client) Netzwerkprogrammierung 1
R Socket FATAL EXCEPTION MAIN bei Socket based client/server app Netzwerkprogrammierung 2
G Server-Client IO Problem Netzwerkprogrammierung 6
ruutaiokwu ständig "sender address rejected: improper use of smtp" bei smtp-client Netzwerkprogrammierung 4
J HTTP [Java 9] Neuer HTTP Client - Tutorial Netzwerkprogrammierung 3
A Chatserver/-client - Code stoppt bei readUTF() Netzwerkprogrammierung 7
I Socket Das erste Server-Client Programm Netzwerkprogrammierung 16
L Zugriffprobleme Client - Webservice AspenTechnology Netzwerkprogrammierung 0
A Client Client Übertragung Netzwerkprogrammierung 12
M Socket Server antwortet dem Client nicht Netzwerkprogrammierung 6
K Socket Netty Client wirft Fehler! Netzwerkprogrammierung 3
I Client/Server Kommunikation bei einem Spiel Netzwerkprogrammierung 4
E Objekte versenden, Client-Server Netzwerkprogrammierung 25
C Mini Client-Server-Anwendung funktioniert nicht Netzwerkprogrammierung 8
U Client Soap Verbindung wieder schließen Netzwerkprogrammierung 0
U Socket Client mit hash authentifizieren Netzwerkprogrammierung 3
F HTTP HTTP Rest Client mit TLS1.2 und selbst signiertem Zertifikat Netzwerkprogrammierung 2
P Server als Client nutzen Netzwerkprogrammierung 8
D Socket Run Args Client/Server Socket Netzwerkprogrammierung 1
Cromewell Socket Multithreaded Server und Client Netzwerkprogrammierung 1
Y Client/Server/DB communication Netzwerkprogrammierung 3
JavaWolf165 Socket mit .writeUtf etwas vom Client zum Server schicken Netzwerkprogrammierung 13
J Client - Serversocket Netzwerkprogrammierung 1
P RMI Client Server Programm über Internet Netzwerkprogrammierung 2
brainless Client Server Kommunikation verschlüsseln Netzwerkprogrammierung 13
gamebreiti Socket Server / Client Anwendung Manipulation von Objekten durch Server Netzwerkprogrammierung 9
T Socket Server/Client Kommunikation Netzwerkprogrammierung 8
N Fragen zu Sockets Client Netzwerkprogrammierung 3
F Extasys TCp Client extends Funktion Netzwerkprogrammierung 0
F Server Client Anwendung mit UDP Netzwerkprogrammierung 2
O Client zwischen XML und JSON auswählen lassen Netzwerkprogrammierung 2
A RMI Wo treten Exceptions bei RMI Aufrufen auf? Auf Client oder auf Server? Netzwerkprogrammierung 3
A ByteBuffer - Client/Server Netzwerkprogrammierung 9
A Socket Wie ein einfacher Multithreads Service mit Telnet als Client mit Observable/Observer gelöst.... Netzwerkprogrammierung 0
K C# Server - Android Client Netzwerkprogrammierung 0
T Application Client NullPointerExc Netzwerkprogrammierung 7
V TCP Client funktioniert auf Emulator aber nicht auf Smartphone Netzwerkprogrammierung 5
H Machbarkeitsfrage: TCP/IP Client (z.B. Netty) für Java Web Applcation Netzwerkprogrammierung 1
P MIME-TYPE Erklaerung, Kommunikation zwischen Client und Server Netzwerkprogrammierung 3
H HTTP REST Jersey - PUT-Beispiel von Client senden Netzwerkprogrammierung 0
J Sichere Kommunikation bei Server Client Netzwerkprogrammierung 3
T Frage zu Client-Server Applikation Netzwerkprogrammierung 2
H Socket Client/Server Socket Programmieren Netzwerkprogrammierung 1
M Theoretische Frage zu Server - Client Netzwerkprogrammierung 2
P HTTP Server / Client Netzwerkprogrammierung 1
N FTP FTP Client invalid IPv6 address (Apache Commons Net API) Netzwerkprogrammierung 6
F TCP Client, verbindung aufrecht halten Netzwerkprogrammierung 0
X RMI: Woher kennt der Client das Schnittstellen-Interface? Netzwerkprogrammierung 2
E Thematik Client server Netzwerkprogrammierung 2
D UDP Client empfängt nichts Netzwerkprogrammierung 2
D Client/Server per Crossover Lan Kabel Netzwerkprogrammierung 1
S Client Server Connection Netzwerkprogrammierung 4
V erste Client - Server Anwendung, paar Fragen wie Socketverbindung checken usw. Netzwerkprogrammierung 4
S Client Anwendung mit zentraler SQL-Datenbank Netzwerkprogrammierung 3
N Client Identifikation eines Servers Netzwerkprogrammierung 1
S Sichere Server/Client Architektur Netzwerkprogrammierung 1
D Chat Server/mehre Client Netzwerkprogrammierung 9
I Server+Client Netzwerkprogrammierung 3
N Client am Server abmelden Netzwerkprogrammierung 0
F Server/Client Probleme Netzwerkprogrammierung 3
D SSH Client Netzwerkprogrammierung 7
U Socket Instant Messanger (Server Linux, Client Windows) Netzwerkprogrammierung 1
B TCP Client Android Netzwerkprogrammierung 3
Athena Grundsatzfragen zu Client-Server-Architektur / Matchmaking Netzwerkprogrammierung 1
A Problem beim Senden von Client zu Server Netzwerkprogrammierung 10
F Client Server DB Netzwerkprogrammierung 0
A Verständnisfrage Multi-Threaded Client/Server Netzwerkprogrammierung 5
F Tipps zum Thema Server/Client vie SOAP Netzwerkprogrammierung 0
OnDemand Ist Client noch angemeldet? Netzwerkprogrammierung 7
F Socket Java - Server/Client simple Netzwerkprogrammierung 1
D Socket UDP Client reagiert nicht auf spontane Meldungen Netzwerkprogrammierung 5

Ähnliche Java Themen

Neue Themen


Oben