Client/ Server, Lesen des Codes

also Ziel ist es einen Client und einen Server zu erstellen…Ich habe einen alten client-code gefunden, aber so richtig check ich das nicht. habe jetzt schon ewig in büchern nachgelesen…

warum wird zum bsp. aus dem string ein char gemacht?? ich habe schon etwas kommentiert, aber so richtig sicher bin ich mir da nicht :(( vllt kann mir ja jemand helfen…das wäre echt nett!


	public static void main(String[] args) {
		try {
			// Anfang Eingabe
			String adresse;
			System.out.print("Adresse mit Port eingeben: ");
			BufferedReader adresseR = new BufferedReader(new InputStreamReader(
					System.in));
			adresse = adresseR.readLine(); // Eingabe auf Adresse

			char[] c;
			c = adresse.toCharArray(); // String in CharArray umwandeln
			String puffer = "";
			String method = "";
			String urlpuff = "";
			int v = adresse.length(); // Laenge des Strings
			int x = 0;
			// Methode auslesen (String bis zum ersten Leerzeichen)
			for (int i = 0; i < v; i++) {
				if (c** != ' ') {
					puffer = puffer + String.valueOf(c**);
				} else {
					method = puffer;
					x = i;
				}
			}

			puffer = "";
			// URL auslesen
			for (int i = (x + 1); i < v; i++) {
				puffer = puffer + String.valueOf(c**);
			}
			urlpuff = puffer;
			URL host = new URL(urlpuff);
			// Zerlegung der URL
			String host1 = host.getHost();
			String protocol = host.getProtocol();
			String path = host.getPath();
			int port = host.getPort();
			if (port < 0)
				port = 80; // fuer den Fall dass Port nicht angegeben wird ist er 80
			System.out.println(path);
			if (path.isEmpty()) {
				path = "/";
			}
			// Anfang Kontrollausgabe
			System.out.println(method);
			System.out.println(protocol);
			System.out.println(host1);
			System.out.println(port);
			System.out.println(path);
			// if (path==null){path= "/index.html";}
			// Ende Kontrollausgabe
			// Ende Eingabe

			// Verbindungsaufbau
			Socket socket = new Socket(host1, port);

			// "Kanal" zum Server
			OutputStream out = socket.getOutputStream();
			OutputStreamWriter out2 = new OutputStreamWriter(out);
			PrintWriter out1 = new PrintWriter(out2);

			System.out.println("vor der anfrage");
			// Anfrage an den Server
			System.out.println(method + ' ' + path + ' ' + protocol);
			System.out.println("Host: " + host1);
			out1.print(method + ' ' + path + ' ' + protocol + "
");
			out1.print("Host: " + host1 + "
" + "
");

			// out1.println("test");
			System.out.println("vor flush");

			out1.flush(); // startet Uebertragung

			// mit BR Antwort vom Server puffern und an s uebergeben
			BufferedReader in = new BufferedReader(new InputStreamReader(
					socket.getInputStream()));
			String s = in.readLine();

			// Abfangen der Codes und sinnvolles Kommentar dazu
			if (s.contains("200")) {
				System.out.println("
" + "Alles ist gut.");
			}
			if (s.contains("400")) {
				System.out.println("
" + "Syntaktisch falsche Eingabe.");
			}
			if (s.contains("404")) {
				System.out.println("
" + "Datei nicht gefunden.");
			}
			if (s.contains("501")) {
				System.out.println("
" + "Serverfehler.");
			}
			System.out.println();
			System.out.println();

			// Ausgabe der ersten Zeile
			System.out.println(s);
			// Ausgabe alller weiteren
			while ((s = in.readLine()) != null)
				System.out.println(s);

			// socket schliessen
			socket.close();

			// BufferedReader schliessen
			in.close();
		}

		catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


An dem Code würde ich micht nicht orientieren. Da sind viele Dinge viel zu kompliziert gemacht.
Schreibe dir den Clientcode lieber selbst und orientiere dich vielleicht hier dran: http://openbook.galileocomputing.de/javainsel9/javainsel_21_001.htm#mjea7bcdd596c8bd25b078a00221a01a75

schade, ich dachte ich könnte den code einigermaßen verwenden. da ich noch blutiger anfänger bin, wäre das ja von vorteil. würdest du sagen, dass einiges überflüssig ist? :verzweifel:

Der Code bastelt auf äußerst krude Weise einen HTTP-Request zusammen und „wertet“ den Response aus, indem er in der ersten Zeile des Responses nach dem Response-Code (200, 400…) sucht.

Weil der Programmierer offensichtlich gerne durch die einzelnen chars iterieren wollte. Ist aber unnötig und auch noch schlecht gemacht (charAt wäre da besser). Mit den String-Methoden substring, indexOf, evtl split und weiteren braucht man das auch überhaupt nicht. An dem Code ist auch noch so viel anderes RICHTIG schlecht, dass ich mich EikeB’s Rat anschließe. Lies Dich etwas ein und mache es neu.

okay vielen dank für die schnellen antworten! ich werde euch mal glauben und etwas neues versuchen…

*** Edit ***

ich habe gerade noch ein feedback von einem kumpel bekommen; das ist quasi genau das was wir suchen^^nur etwas blöd geschrieben (anscheinend) könnte mir bitte jemand einen kleinen denkanstoß für das charAt bspw. geben? :o wir versuchen den code nur etwas schöner zu gestalten…

Vergiss die Idee fertigen Code im Internet zu finden den du wiederverwenden kannst. Selbst wenn du fündig wirst, ist das anpassen des Codes aufwendiger als es selber zu schreiben.

String#charAt(int)

Es wird ein Socket geöffnet, das ist alles, um was es sich da dreht.

String-Processing/-Iteration kann so oder so gemacht werden, auch Strings aus dem String-Pool sind ja immutable, .contains() ist ein guter Anfang.

Hmm, kommt drauf an, unterhalten oder lernen? Dann selber/selbst schreiben. Sonst hab ich wirklich keinen Schimmer, ob’s dazu ein gutes Buch gibt. Grüße, schönen Sonntag von Cyborg.

Hier ich stelle zur Diskussion:

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        InputStream is = null;
        try {
            URL url = new URL(urlStr);
            URLConnection urlc = url.openConnection();
            urlc.setRequestProperty("User-Agent", "something magic happens here");
            urlc.setConnectTimeout(2 * 5000);
            urlc.setReadTimeout(2 * 5000);
            is = urlc.getInputStream();
            int b;
            while ((b = is.read()) != -1) {
                baos.write(b);
            }
        } catch (Exception ioe) {
            System.out.println("ioe = " + ioe);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ioe) {
                    System.out.println("ioe = " + ioe);
                }
            }
        }
        return baos.toByteArray();
    }

    public static String baToString(byte[] ba) throws IOException {
        StringBuilder sb = new StringBuilder(ba.length);
        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(ba), "iso-8859-1");
        int c;
        while ((c = isr.read()) != -1) {
            sb.append((char) c);
        }
        isr.close();
        return sb.toString();
    }```

Nun, url und urlc sind ja nun kein Socket im eigentlichem Sinn. urlStr und URL bis "InputStream" verwandeln ja in etwas Magisches, bevor das erste Byte gelesen werden kann. Irgendwo wird da ein Protokoll auf Port 80 implementiert sein, das man irgendwie kümmern muss.

Lies etwas über ein Chatsystem. Klingt blöd, aber bei mir ich finde das Buch darüber nicht wieder.

Mein Code darf übrigens nicht verwendet werden.

@CB
Sorry Buddy, dein Ansatz in allen Ehren, aber leider genau so daneben wie das von TO gepostete Beispiel.
Ich geh es einfach mal Zeile für Zeile durch.

4 : Man könnte sich durch try-with-resources das anschließende finally mit geschachteltem try-catch für das close() ersparen.
8/9 : Wirklich ? 2x5000 statt direkt 10000 ? Es wird zwar vom Compiler eh weg optimiert, warum aber erst so umständlich in den Source schreiben ?
11-14 : auch wenn Byte-weise lesen möglich ist nutzt man dafür normalerweise ein Byte-Array. Wenn man dann noch die Response-Length liest und mit DataInputStream arbeitet kann man sich sowohl den Loop als auch den ByteArrayStream komplett sparen und mit readFully() alles direkt in ein Array lesen.
16/22 : In ein catch() gehört grundsätzlich IMMER ein Throwable.printStackTrace() !
29 ff : Davon abgesehen das es auch ByteArrayOutputStream.toString() gibt (was hier natürlich um auch Binärdaten laden zu können clevererweise nicht genutzt wurde) könnte man auch dem Konstruktor String(byte[]) nutzen und dem Compiler die Optimierung überlassen. Da noch umständlich mit ByteArrayInputStream und StringBuilder und weis der Geier rumhampeln verwirrt eher und dürfte auch nicht wesentlich eleganter sein als Methoden die es bereits in der SE-API gibt (zu mal die Variante "new String(byte[]) das deutlich eleganter macht als der StringBuilder).

Also eher “meh” der Krams …

Und dem Hinweis das der Code (so) nicht verwendet werden darf (was auch immer du uns damit sagen willst) würde ich nur entgegnen : Warum sollte man ? Geht deutlich eleganter/besser.
(Wobei die Grundstruktur URL > URLConnection > read() ja nun mal nicht geändert werden kann.)

Unsinnig ist auch, das lade keine Exception wirft, byteArrayToString hingegen schon, obwohl diese Methode wahrscheinlich nie eine Exception auslöst. Aber wahrscheinlich hab ich mir gedacht, wenn nix oder teilweise gelesen wird, wird leer oder teilweise zurückgegeben.

Ich weiß net, mit welchem charset „new String(byte[])“ arbeitet, UTF-16 wäre bei Websites schlecht. isr.close(); ist überflüssig, diese Methode gibt ja im nächsten Schritt was zurück.

Gut lädt alles, was URL als Argument/Parameter übergeben werden kann (http…).

Bevor es Java 7/8 gab, sollte das try-catch-finally-Konstrukt immer (genau) so geschrieben werden, das hab ich mir nicht ausgedacht, das steht in den offiziellen Tutorials dazu. Netbeans hat was gegen .printStackTrace() (kein Fehler, aber meckert), wahrscheinlich ein Benutzer kann damit nix anfangen. Deswegen kurze Meldung auf .in anstatt .err .

Aber egal. Soweit ich das überblicken kann, sollte oben ein Teil des http-Protokolls implementiert werden, und mindestens der response status code gelesen werden. Deswegen hab ich die zwei Methoden gepostet. :wink:

Edit: 2 * 5000 deswegen, weil hervorgehoben werden sollte, 1. wert, 2. durch besonderen wert ersetzen, 3. das für 100-300 KiB eigentlich immer ausreichend.

Alles etwas durcheinander (einzelne Absätze), nicht schlimm, wa wissen ja, was gemeint ist. Ich schreib’ immer hab anstatt habe/n, netd anstatt nicht, kleinschreiben anstatt großschreiben (nicht lowerCamelCase), und alles mit Bindestrich, es sei denn, direkt aus dem Englischen zitiert/C’n’P (und Kommas mehr als nötig).

Ähm, WAT IS ? Mal ganz erlich : wie viele Leute nutzen den Account / haben Zugriff drauf ?

“Ich weiß net, mit welchem charset “new String(byte[])” arbeitet” -> Dann schau halt in die Doc : https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#String-byte:A-
Normalerweise sollte eigentlich eine Angabe zu finden sein, dann kann man auch “new String(byte[], Charset)” nutzen -> https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#String-byte:A-java.nio.charset.Charset-

“Bevor es Java 7/8 gab, sollte das try-catch-finally-Konstrukt immer (genau) so geschrieben werden, das hab ich mir nicht ausgedacht, das steht in den offiziellen Tutorials dazu.” -> Gut, muss ich zu geben : habe ich mich nicht weiter mit befasst, aber da ich eh auf dem aktuellen JDK-8 arbeite nutze ich solche Vorteile (hab mich mitlerweile dran gewöhnt).

“Netbeans hat was gegen .printStackTrace() (kein Fehler, aber meckert)” -> Kann ich mir jetzt erlich gesagt eigentlich nicht wirklich vorstellen, prüf mal deine Templates, vielleicht hast du da mal was dran geändert. Außerdem ist es gängige Praxis das man den StackTrace entweder direkt auf .err ausgibt (über printStackTrace()) oder zumindest irgendwie loggt. Das eine IDE hier bewusst lieber auf Throwable.toString() geht … schon sehr merkwürdig.

Und deine Erklärung warum du nun “2x5000” statt “10000” geschrieben hast ergibt leider (für mich) keinen Sinn.

nicht so fundamental werden,

mit Suchfunktion aus April Beispiel zu finden, gar ‚Best Practice‘, freilich vielleicht erst seitdem zu dieser Regel gekommen:

[quote=Sen-Mithrarin;91070] try { d=crypt(c); } catch(IOException ioe) { throw ioe; } catch(ShortBufferException sbe) { throw new IOException(sbe); } catch(IllegalBlockSizeException ibse) { throw new IOException(ibse); } catch(BadPaddingException bpe) { throw new IOException(bpe); }[/quote]
ist schon ein gutes Gegenbeispiel,

noch allgemeiner ist eine grundsätzliche gute (wenn nicht bessere) Alternative, eine neue RuntimeException zu werfen, damit Prozesse beendet werden,
an höherer Stelle sicher dann die Ausgabe,
stattdessen evtl. nur printStackTrace() und im Code weiter machen kann unschön enden

im catch einer InterruptedException, ob Verwendung nie geplant oder mit wait/notity im aktiven Einsatz, braucht es keine sinnlose Ausgabe

und wenn man ein wenig weiß was man tut (soviel kannst du CB doch zugestehten, an Neulinge wäre sonst auch freundlicherer Hinweis passend, diese Form nie gut,
abgesehen davon dass es sich kaum lohnt, mit CB zu streiten), reicht an gewissen Stellen, gerade in kleinen Programmen, auch einzeilige Ausgabe,
die Art der Exception evtl. auch so mitzubekommen, StackTrace hilft weder für weitere Tiefe der Aufrufe innerhalb des catches, noch zum Auffinden des konkreten catches im Code

*** Edit ***

.err kann sogar Schwierigkeiten machen bei vielen anderen Ausgaben nebenher, Reihenfolge durcheinander,
verbreiteter ist Ausgabe nach .err aber natürlich

Hier schreibt (eigtl.) nur eine Person, aber ich hab mir (leider) unterschiedliche Schreibstile angewöhnt. binär ist das ja auch kein Probl.

Ich kenne die Docs. Wenn ein ‘Umbruch’ beim Lesen des Codes stattfindet, erhöht das Aufmerksamkeit auf de Textstelle. So… nachdem ich nachgelesen hab, zwischen url, urlc und is befindet sich eine HTTP-Handler und ein Content-Handler. -> Wird von subclasses implementiert. HTTx-Protokoll weiter lesen.

BufferedReader liest ja nur eine Zeile oben, denke, das Thema is’ durch. Grüße nochmal.

Hallo Leute,

ich bin echt überrascht, wie viele sich hier auf meinen Hilferuf gemeldet haben! danke!! :slight_smile:

ich habe mich nochmals rangesetzt und etwas zusammengeschrieben:

 * @author...Die Client Klasse baut eine
 *         Verbindung zu einer aus der Konsole angegebenen Internetadresse auf.
 */
public class client {

	public static void main(String[] arfs) {

		try { // Try Catch Block

			// 1. Eingabe auslesen
			InputStreamReader iReader = new InputStreamReader(System.in);
			BufferedReader bReader = new BufferedReader(iReader);
			System.out.print("Gib eine Sever-Adresse eventuell mit einem Port ein: 
");
			String userInputs = bReader.readLine();
			String[] inputTails = userInputs.split(" ");

			// 2. Eingabe verarbeiten
			String urlPart = "";
			String method = inputTails[0];
			urlPart = inputTails[1] + ' ' + inputTails[2]; // bei localhost ist protocol 'default'
			urlPart.toString();

			System.out.println(urlPart);

			// 3. URL in Domain, Protokol, Pfad und Port teilen
			URL host = new URL(urlPart);
			String domain = host.getHost();
			String protocolType = host.getProtocol();
			String path = host.getPath();
			int clientPort = host.getPort();

			// Wenn kein Pfad existiert
			if (path.isEmpty()) {
				path = "/";
			}

			// Wenn der Port nicht angegben wurde oder negativ ist
			if (clientPort <= -1) {
				clientPort = 80;
			}
			// 4. Kontrollausgaben
			System.out.println("Ausgewerte Eingabedaten :
" + "Protocal: "
					+ protocolType + '
' + "Methode: " + method + '
'
					+ "Host: " + domain + '
' + "Pfad: " + path + '
'
					+ "Port: " + clientPort);

			// 5. Socket-Kanal ˆffnen - Verindungsaufbau
			Socket client = new Socket(domain, clientPort); // Socket wird host und port ¸bergeben
			System.out.println("client gestartet");

			// 6. Anfrage an Server - ‹bertragung starten
			OutputStream out = client.getOutputStream();
			PrintWriter pWriter = new PrintWriter(out);

			// wird dem Server geschrieben
			pWriter.write("Hallo Server!");
			pWriter.write(method + ' ' + path + ' ' + protocolType + "
");
			pWriter.write("Host: " + domain + "
" + "
");

			// 7. Serverantworten auslesen
			InputStream iStream = client.getInputStream();
			BufferedReader bReader2 = new BufferedReader(new InputStreamReader(
					iStream));

			String catchComment = bReader2.readLine();

			switch (catchComment) {
			case "200":
				System.out.println("
" + "Alles ist gut.");
				break;
			case "400":
				System.out.println("
" + "Syntaktisch falsche Eingabe.");
				break;
			case "404":
				System.out.println("
" + "Datei nicht gefunden.");
				break;
			case "501":
				System.out.println("
" + "Serverfehler.");
				break;
			default:
				System.out.println("
" + "Keine Ahnung.");
			}

			// mit flush wird aktualisiert - sonst wird nicht gesendet
			pWriter.flush();

			// 8. Socket-Kanal schlieflen
			pWriter.close();
			bReader2.close();

		} catch (UnknownHostException hostFail) {
			hostFail.printStackTrace();
		} catch (IOException ioFail) {
			ioFail.printStackTrace();
		}
	}
}```

nun muss ich nur noch Fehlermeldungen einbauen...



ich hab da zwar schon etwas, aber geht das auch schöner? was meint ihr? :)

..jemand vielleicht einen geistesblitz?
danke schonmal!!

Mach’ das doch so, ist zwar ein Trainwreck (würde Landei jetzt sagen), aber egal:

            @Override
            public void run() {
                try {
                    ServerSocket sock = new ServerSocket(80); // or 0
                    Socket sock2 = sock.accept();
                    sock.close();
                    BufferedReader br = new BufferedReader(new InputStreamReader(sock2.getInputStream()));
                    String lin;
                    while ((lin = br.readLine()) != null && !lin.isEmpty()) {
                        System.out.println(lin);
                    }
                    System.out.println(lin);
                    PrintWriter pw = new PrintWriter(sock2.getOutputStream());
                    pw.println("Status: HTTP/1.1 200 OK");
                    pw.flush();
                    sock2.close();
                } catch (IOException ioe) {
                    System.out.println("ioe = " + ioe);
                }
            }
        }).start();
        Pattern pat = Pattern.compile("^.*?(\\d{3,}).*$");
        URL url = new URL("http://localhost/nenDatei/");
        BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
        String lin;
        while ((lin = br.readLine()) != null) {
            System.out.println(lin);
            Matcher mat = pat.matcher(lin);
            if (mat.find()) {
                short status = Short.parseShort(mat.group(1));
                System.out.println("status = " + status);
            }
        }
        br.close();```


GET /nenDatei/ HTTP/1.1
User-Agent: Java/special version(geheim)
Host: localhost
Accept: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2
Connection: keep-alive

Status: HTTP/1.1 200 OK
status = 200



In `status` steht nun der Status-Code. Normalerweise try-catch-finally- usw. `localhost` wird ja aufgelöst.

Edit: Normalerweise kommt jede ServerSocket, Socket und URLConnection in eine eigene Klasse/Runnable, aber etwas komprimiert.

Der Server antwortet immer mit einer Statuszeile. Probl behoben?

hey, das sieht schon sehr gut aus :slight_smile:

ich kann ja mal kurz zeigen, was am ende wirklich rauskommen soll:

:confused:

Hmm, ich würde sagen, baue den Request gerade selbst, aber das ist stümperhaft, andererseits kann man URLConnection nicht gerade sagen, bitte der und der Request mal zurückgeben, um ihn abzuschicken. Ich sieh’s mir morgen noch-mal an, wenn niemand 'ne Idea hat.

Danke für Deine Hilfe! Eigentlich fehlt ja “nur” noch diese HTML Geschichte in der Ausgabe…