ChatServerHandler

flashray

Erfahrenes Mitglied
Hallo,

arbeite gerade ein Beispiel aus dem Buch "Killer Game Programming in Java" durch:
http://fivedots.coe.psu.ac.th/~ad/jg/

Unzwar eine Beispielapplikation aus dem 30. Kapitel:
http://fivedots.coe.psu.ac.th/~ad/jg/ch19/index.html

Threaded TCP Clients and Server.

Die 6 Klassen habe ich hier hochgeladen:
http://www.qalem.de/temp/


Mir ist nicht verständlich, warum nach einer Anfrage des Clienten die while-Schleife in der Methode processClient() nicht verlassen wird. Wenn der Inhalt des BufferedReaders leer ist, müsste doch die Schleife beendet werden. Dies ist jedoch nicht der Fall. Der Client ist so lange verbunden mit dem Server über ein und den selben ServerHandler bis der Chatclient sich verabschiedet.


Meine ähnlich aufgebaute Testanwendung endet schon bald.

Java:
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;

public class StreamTest {

	public static void main(String[] args) throws IOException {
		String s = "Hallo wie geht es dir?\nMir geht es gut!";
		InputStream is = new ByteArrayInputStream(s.getBytes());
		BufferedReader buf = new BufferedReader(new InputStreamReader(is));

		OutputStream os = System.out;
		PrintWriter pw = new PrintWriter(os);

		boolean done = false;
		String line = "";
		int i = 0;
		while (!done) {
			System.out.println(i++);
			if ((line = buf.readLine()) == null)
				done = true;
			else {
				System.out.println("Client: " + line);
				if (line.trim().equals("bye"))
					done = true;
				else
					pw.println("doRequest");
			}
		}
	}
}


Hier kann man sich den SourceCode runterladen:
http://fivedots.coe.psu.ac.th/~ad/jg/code/ch30Code.zip

Java:
package Threaded;

// ChatServerHandler.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th
/*
 A threaded ChatServerHandler deals with a client.

 Details about a client are maintained in a ChatGroup 
 object, which is referenced by all the threads.

 The ChatGroup object handles message broadcasting
 via its broadcast() method.

 Possible client messages:
 who				-- a list of users is returned
 bye             -- client is disconnecting
 any text		-- which is broadcast with
 (cliAddr,port): at its front 
 */

import java.net.*;
import java.io.*;

public class ChatServerHandler extends Thread {
	private Socket clientSock; // client details

	private String cliAddr;

	private int port;

	private ChatGroup cg; // shared by all threads

	public ChatServerHandler(Socket s, ChatGroup cg) {
		System.out.println("ChatServerHandler()");
		this.cg = cg;
		clientSock = s;
		cliAddr = clientSock.getInetAddress().getHostAddress();
		port = clientSock.getPort();
		System.out.println("Client connection from (" + cliAddr + ", " + port
				+ ")");
	} // end of ChatServerHandler()

	public void run() {
		System.out.println("run() ->");
		try {

			// Get I/O streams from the socket
			BufferedReader in = new BufferedReader(new InputStreamReader(
					clientSock.getInputStream()));
			PrintWriter out = new PrintWriter(clientSock.getOutputStream(),
					true); // autoflush

			cg.addPerson(cliAddr, port, out); // add client details to
												// ChatGroup

			processClient(in, out); // interact with client

			// the client has finished when execution reaches here
			cg.delPerson(cliAddr, port); // remove client details
			clientSock.close();
			System.out.println("Client (" + cliAddr + ", " + port
					+ ") connection closed\n");
		} catch (Exception e) {
			System.out.println(e);
		}
		System.out.println("run() |");
	} // end of run()

	private void processClient(BufferedReader in, PrintWriter out)
	/*
	 * Stop when the input stream closes (is null) or "bye" is sent Otherwise
	 * pass the input to doRequest().
	 */

	{
		System.out.println("processClient()");
		String line;
		boolean done = false;
		try {
			while (!done) {
				System.out.println(done);
				if ((line = in.readLine()) == null)
					done = true;
				else {
					System.out.println("Client (" + cliAddr + ", " + port
							+ "): " + line);
					if (line.trim().equals("bye"))
						done = true;
					else
						doRequest(line, out);
				}
				System.out.println(line);
			}
		} catch (IOException e) {
			System.out.println(e);
		}
	} // end of processClient()

	private void doRequest(String line, PrintWriter out)
	/*
	 * The input line (client message) can be : who -- a list of users is
	 * returned or any text -- which is broadcast with (cliAddr,port) at its
	 * front
	 */
	{
		if (line.trim().toLowerCase().equals("who")) {
			System.out.println("Processing 'who'");
			out.println(cg.who());
		} else
			// use ChatGroup object to broadcast the message
			cg.broadcast("(" + cliAddr + ", " + port + "): " + line);
	} // end of doRequest()

} // end of ChatServerHandler class


Vg Erdal
 
Ich bin mir nicht ganz sicher, aber das Verhalten scheint mir richtig zu sein.
Ich denke die Methode
Java:
readLine()
der Klasse BufferedReader wird eine blockierende Methode sein, d.h. sie gibt eigtl. nur null zurück, wenn der Stream geschlossen wird, ansonsten wartet sie bis neue Daten verfügbar sind.
Der Unterschied zu deinem Beispiel ist, dass du einen Stream festlegst, der eine fest Größe hat. Nach dem letzten Zeichen ist dieser zu Ende und readLine() liefert null.
Ein Socket-InputStream hingegen wartet immer auf neue Eingaben des Clients, was ja auch sinnvoll ist.
Hoffe meine Ausführung ist verständlich :)

Gruß
Tobias
 
Hallo Tobias,

Deine Erklärung scheint mir plausibel ;) .

Bin gerade dabei selber Netzwerkklassen für eine Applikation nach diesem Muster zu implementieren, an dieser Stelle war ich aber hängen geblieben.

Danke für die schnelle Hilfe!


Vg Erdal
 
Zurück