# IP-Adressenpool berechnen



## Mampf (22. Okt 2011)

Hallo!

Tut mir leid, dass ich euch schon wieder hier "belästige", aber ich bräuchte dringend Hilfe, da ich bei der derzeitigen Hausaufgabe relativ planlos bin.

Aufgabenstellung: Ich soll eine IP-Adresse und eine Subnetzmaske eingeben und dann die Anzahl der möglichen IP-Adressen berechnen lassen.

Hier kommt schon die erste Hürde: Fürs Umrechnen von Dezimal zu Binär sollen wir eine eigene Umrechner-Klasse samt Methode schreiben. Ich hätte das bei einer vorhergehenden Aufgabe zwar schonmal mit 
	
	
	
	





```
Integer.toBinaryString()
```
 versucht, mein Lehrer war da allerdings nicht all zu begeistert (ich soll die Methode gefälligst selbst schreiben), und für diese Aufgabe wird ja wegen der Dezimalpunkte auch ein String benötigt.
Jetzt weiß ich zwar, wie ich händisch vom Dezimal ins Binärsystem umwandle (Potenz von 2 suchen, die in die Zahl passt, dann abziehen, mit dem Rest dasselbe machen, bis 0 Rest bleibt), wie das ganze allerdings in Java realisiert werden kann ist mir noch etwas schleierhaft.

Außerdem verstehe ich noch nicht ganz, wie die gegebene IP dann Einfluss auf die Anzahl der Möglichkeiten hat, bzw. wie das mit dem Netzwerk- und dem Hostteil richtig funktioniert.

Ich hoffe, hier findet sich jemand, der mir das Ganze relativ geduldig erklären kann - bis zum Abgabetermin ist auf alle Fälle noch jede Menge Zeit (Mittwoch in einer Woche), es geht mir jetzt nicht so sehr um eine schnelle Lösung, sondern eher um das vollständige Verstehen von solchen Zahlenumwandlungen, da dies eigentlich schon immer ein Schwachpunkt von mir beim Programmieren war.

Danke, Mampf.


----------



## nillehammer (22. Okt 2011)

Hallo,

stimmt für die Anzahl möglicher IP-Adressen ist nur die Subnetzmaske entscheidend. Aber das Programm soll bestimmt noch erweitert werden um die Anzeige der möglichen IPs. Dann braucht man natürlich auch die IP-Adresse. Die Berechnung der möglichen Anzahl von IP-Adressen ist eigentlich ganz leicht. Dazu folgendes Beispiel

Netzmaske Dezimal:
255.255.255.0
Netzmaske Binär:
11111111 11111111 11111111 00000000

Da bei einer Netzmaske die Nuller-Stellen der Bereich für die Hosts sind, musst Du die Maske einfach invertieren (sprich jede 1 zu 0 und jede 0 zu 1). Der resultierende Wert ist dann die Anzahl möglicher IP-Adressen. Ggf. noch minus zwei, um Broadcast und Netznummer herauszurechnen.

Bits invertieren geht mit den Bit-Operatoren von Java. Siehe z.B. hier: Java Notes: Bitwise Operators

P.S. Und dann noch ein Tipp: Speichere die Netzmaske und IP-Adresse als Long-Werte ab. Wenn Du sie in Integer packst, bekommst Du Schwierigkeiten mit der Interpretation bestimmter Werte, die von Java als negativ angesehen werden (Stichwort Zweier-Komplement)


----------



## nillehammer (22. Okt 2011)

Nochmal ich.
Der Algorhitmus zum Parsen eines Stings in einen IP-Wert:

```
- String nach den punkten splitten --> Ergebnis ein Array mit vier Strings, die die vier Nummern darstellen
- Einen long mit Wert 0 initialisieren
- Den Array durchiterieren
  - String nach int parsen
  - Den geparsten int mit dem long-Wert per binärem Oder verknüpfen
  - Wenn nicht das letze Element, dann in den long-Wert 8 Bits nach links shiften
```

Algorithmus zur Ausgabe des IP-Werts als String

```
-Finde den long-Wert, dessen 8 letzte Bits aus 1en bestehen und sonst nur 0en. Das ist Deine Bitmaske
- Initialisiere Dir einen Array, der 4 int-Werte aufnehmen kann.
-Verknüpfe die Bitmaske mit dem long-Wert, der Deine IP enthält, per binärem Und (wichtig: überschreibe ihn dabei nicht). Ergebnis: Die letzte Stelle Deiner IP.
Speichere diesen in der letzten Position Deines Arrays
-Shifte den long mit Deiner IP unsigned 8 Bits nach rechts
- Wiederhole die letzten zwei Schritte noch 3 Mal, bis Du den Array gefüllt hast
Iteriere Durch den Array und bau Dir mit einem StringBuilder den Ausgabestring zusammen
```


----------



## Mampf (22. Okt 2011)

Danke für die schnelle Antwort!

Ich hätte ja eigentlich gedacht, das alles in Strings zu speichern, sind die Dezimalpunkte hier irrelevant?

Außerdem hab ich die Aufgabenstellung nochmal gelesen, da gibt's auch ein konkretes Beispiel.

Eingegebene Netmask: 255.255.255.240
Eingegebene IP: 113.8.66.42
Ausgabe: Der gesuchte IP-Pool lautet 113.8.66.33 bis 113.8.66.46.

Wie komme ich jetzt am besten zum Pool (also wie mache ich das von - bis)?

Danke.


----------



## nillehammer (22. Okt 2011)

> Ich hätte ja eigentlich gedacht, das alles in Strings zu speichern, sind die Dezimalpunkte hier irrelevant?


Genau wegen der gestellten Aufgaben kannst Du die Werte nicht als Strings speichern. Mit den Strings kannst Du eben leider nicht rechnen. Mit den long-Werten schon. Eine IP-Adresse/Subnetzmaskte ist nicht anderes als 4 Bytes, die der besseren Lesbarkeit wegen mit Punkten getrennt werden. Wenn Du diesen String richtig parst und die Werte der Bytes an die richtige Stelle in einem long schiebst, spielen die Punkte keine Rolle.



> Wie komme ich jetzt am besten zum Pool (also wie mache ich das von - bis)?


In meinem ersten Post habe ich beschrieben, wie Du die Anzahl möglicher IPs herausbekommst
In meinem zweiten Post habe ich beschrieben, wie Du die Strings in long-Werte parst, mit Denen du rechnen kannst.
Von-Bis ist jetzt nur noch niedrigster Wert plus mögliche Anzahl.
Wie man die Werte ausgibt, steht auch in meinem zweiten Post.

Ich schlage vor, dass Du die beschriebenen Algorhitmen in Java als statische Methoden implementierst. Dazu fülle folgende Rümpfe:

```
public final class IpConverter {
  public static final long ipStrAsLong(final String ipStr){
     ...
  }

  public static final String longAsIpStr(final long value) {
    ...
  }
}
```

Wenn es dabei Probleme gibt, machen wir dann konkret weiter.


----------



## Mampf (22. Okt 2011)

Ups, dein zweiter Post dürfte gekommen sein, während ich an meinem geschrieben habe, sieht schon ziemlich aufschlussreich aus 

Ich werde auf jeden Fall mal versuchen, die beiden Methoden zu vervollständigen...


----------



## Mampf (23. Okt 2011)

So, die Splitterei funktioniert schon, allerdings denke ich, dass ich beim Parsen etwas falsch mache, da folgende Exception auftritt:


```
Exception in thread "main" java.lang.NumberFormatException: For input string: "255"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:492)
	at Uebung2.IpConverter.ipStrAsLong(IpConverter.java:14)
	at Uebung2.UI.main(UI.java:24)
Java Result: 1
```

Mein Quellcode hierzu:

```
for(int i = 0; i < strArray.length; i++) {
        int temp = Integer.parseInt(strArray[i],2);
        IO.write(temp + " ");
    }
```
(das IO.write ist bloß drin, um zu schauen, ob der ausgegebene Wert stimmt)


----------



## nillehammer (23. Okt 2011)

Du versuchst, den String "255" als Binärzahl zu parsen. Bei Binärzahlen sind als Ziffern nur 0 und 1 erlaubt. Deswegen bekommst Du die NumberFormatException. Du brauchst die Zahlen aber garnicht im Binärformat zu parsen und zu verarbeiten. Nimm einfach die ganz normale parseInt-Methode.


----------



## Mampf (24. Okt 2011)

Ok, wenn ich das jetzt richtig verstanden habe, soll ich alle ints im Array in den Ergebnis-long schreiben lassen? (Also wenn jetzt im Array 255 255 254 0 sind, wird der long zu 2552552540?). 
Und könntest du mir bitte erklären, wie dieses bitweise Shiften funktioniert?
Die Prüfung, ob es der letzte Wert ist, ist ja klar, das sollte mit 

```
if(i != (strArray.length - 1) {
  //Shift
}
```
in der for-Schleife funktionieren.


----------



## nillehammer (24. Okt 2011)

-Du hast einen long mit 0 initialisiert
-Du hast die erste Stelle einer IP oder Netzmaskte geparst (ist egal, das Verfahren ist dasselbe). Sagen wir 255
-Du verknüpfst den int mit binärem Oder mit dem long. In dem long steht jetzt dezimal 255. Binär ist das:
00000000000000000000000000000000000000000000000000000011111111
Dazu brauchtst Du nichts umzurechnen oder so. Das ist halt die interne Darstellung eines long-Wertes
-Shiften heißt, Bits von rechts oder links in das Feld hineinzuschieben. Wir benutzen hier right-Shift mit 8 bits. Beim right-Shift werden von rechts einfach Nullen in das Bitmuster geschoben mit 8 Bits ergibt sich dann folgender Wert:
00000000000000000000000000000000000000000000001111111100000000
Du siehst, die letzten 8 Bits (also das letzte Byte) Deines long sind jetzt wieder 0. Jetzt machst Du die nächste Oder-Verknüpfung mit dem zweiten geparsten Wert schiebst wieder 8 0-Bits rein usw.

Bei Deiner Beispielmastke 255.255.254.0 ergibt sich dann folgdendes Bitmuster:
0000000000000000000000000000000011111111111111111111111000000000
Was der Dezimalzahl 4294966784 entspricht und nicht 2552552540.

Zur Erinnerung: Eine Übersicht über die binären Operatoren von Java findest Du z.B. hier: Java Notes: Bitwise Operators

Ist das verständlich erklärt? Sollen wir vielleicht nochmal einen Schritt zurück machen und klären, warum wir hier mit Shifting arbeiten?


----------



## Mampf (24. Okt 2011)

> Sollen wir vielleicht nochmal einen Schritt zurück machen und klären, warum wir hier mit Shifting arbeiten?



Ja bitte, das wäre sehr nett.
Wie es geht habe ich nach dem Durchlesen des Bitwise Operation Links verstanden, denke ich mal,also mein Code müsste dann so aussehen: (in der for-Schleife)

```
result = result|temp //result ist der long und temp der int
```
und im if-Block dann: 
	
	
	
	





```
result >> 8
```

Aber warum das ganze so geht ist mir noch nicht ganz klar.


----------



## nillehammer (24. Okt 2011)

Moin,
erst mal Entschuldigung. In meinem letzten Post habe ich einen Fehler drinnen. Es muss natürlich (wie auch in richtig in der Beschreibung der Algorhitmen steht) *left shift* heißen. Wir wollen die Bits ja nach links schieben. Der richtige Operator wäre dann "<<". Nochmal sorry dafür. Ansonsten stimmt der Code.

Nun zur Erklärung:
Grundsätzlich alles, was man sich so an Prüfungen mit IP-Adressen vorstellen kann, z.B.
-IPs sortieren
-Prüfen, ob IP in einem best. Subnetz?
-Anzahl möglicher Hosts in einem best. Subnetz berechnen
-Bei Angabe eines Subnetz-Strings prüfen, ob dieser gültig ist, oder vielleicht sogar sinnvoll reagieren.
Das alles geht nur, wenn man mit Zahlen statt Strings arbeitet. Soweit waren wir ja schon.

Jetzt ist die Frage, wie man einen IP-String "192.168.1.1" oder einen Subnetz-String "255.255.254.0" am sinnvollsten als Zahl speichert. Wenn man sich überlegt, was die Strings eigentlich bedeuten, kommt man darauf, dass es sich um 4 Bytes handelt. Wichtig ist noch, dass die Zahlen vorzeichenlos positiv sind.

In der ersten Näherung könnte man einfach die vier Zahlen parsen und in einem Array mit Länge 4 speichern. Das würde das Parsen und wieder Ausgeben sehr einfach machen. Allerdings wären alle anderen Funktionen (siehe Liste oben) sehr umständlich zu programmieren. (Warum das so ist, kommt später. Im Moment glaube es mir einfach mal.)

Viel einfacher ist es, die Werte in eine *einzige* Zahl zu speichern. Wenn man die vier Bytes in einer einzigen Zahl (bei uns ein long) speichert, muss man natürlich wie bei dem Array beachten, dass die Zahlen jeweils an der richtigen Stelle landen. Die Zahl an der ersten Stelle einer IP ist das viert-letzte Byte, die an der zweiten Stelle das Dritt-letzte, die an der dritten Stelle das Vorletzte und die an der vierten Stelle das letzte Byte. Mit dem Shiften sorgen wir dafür, dass wir die Bytes schrittweise dorthin schieben, wo sie hin gehören.

Also langer Rede kurzer Sinn: Eine IP-Adresse/Subnetz-Angabe ist nichts anderes als eine vorzeichenlose Zahl mit 4 Bytes * 8 Bit pro Byte = 32 Bits. Und diese Verknüpfungen und das Shiften machen wir, um aus dem String mit 4 Stellen genau das zu machen.

Die Methode "ipStrAsLong" ist ja nun fast fertig. Sei bitte so nett und poste mal den vollständigen Code der Klasse "IpConverter " zur Kontrolle.


----------



## Mampf (24. Okt 2011)

So, mein Quellcode bis jetzt:


```
public static final long ipStrAsLong (final String ipStr) {
    
    long result = 0;
    String[] strArray; //String-Array erzeugen
    String splitExp = "\\."; //den Punkt escapen, sonst funktioniert es nicht
    strArray = ipStr.split(splitExp); //String bei den Punkten splitten und ins Array schreiben
    
    for(int i = 0; i < strArray.length; i++) {
        int temp = Integer.parseInt(strArray[i]);
        result = result|temp; //long result mit int temp verknuepfen
        
        if(i != (strArray.length -1)) { //wenn nicht am Ende des Arrays angelangt, 8 Bits nach links shiften
            result = result << 8;
            
        }
    }
    
    return result;
    }
```

Also habe ich das richtig verstanden, dass wir eigentlich vier Zahlen in eine packen(wo dann die einzelnen Bytes für die Zahlen stehen)?


----------



## nillehammer (24. Okt 2011)

Super, der erste Schritt ist geschafft. Ich habe nur noch zwei kleine Verbesserungsvorschläge. Siehe nachfolgender Code:
[Java]
public final class IpConverter {

  // 1. Hier macht eine Konstante mehr Sinn, als die Deklaration in der Methode.
  private static final String SPLIT_EXP = "\\.";

  public static final long ipStrAsLong (final String ipStr) {

    long result = 0;
    // 2. Deklaration und initialisierung kann in eine Zeile.
    final String[] strArray= ipStr.split(SPLIT_EXP); //String bei den Punkten splitten und ins Array schreiben

    for(int i = 0; i < strArray.length; i++) {
        final int temp = Integer.parseInt(strArray_);
        result = result|temp; //long result mit int temp verknuepfen

        if(i != (strArray.length -1)) { //wenn nicht am Ende des Arrays angelangt, 8 Bits nach links shiften
            result = result << 8;

        }
    }

      return result;
  }
}
[/Java]




			Also habe ich das richtig verstanden, dass wir eigentlich vier Zahlen in eine packen(wo dann die einzelnen Bytes für die Zahlen stehen)?
		
Zum Vergrößern anklicken....

Ja, genauso ist es._


----------



## Mampf (24. Okt 2011)

Juhu, schön langsam verstehe ich das Konzept  Deine Verbesserungsvorschläge habe ich auch dankend angenommen.
Bis jetzt war das auf alle Fälle schon eine sehr lehrreiche Erfahrung für mich (Bits herumgeschoben habe ich vorher überhaupt noch nie.

Damit ich das ganze meinem Lehrer aber auch zufriedenstellend erklären kann, würde ich gerne wissen ob meine Beschreibung von ipStrAsLong stimmt:


```
/***********************************************************************************
      * ipStrAsLong: Methode um eine IP-Adresse von einem String in einen long zu packen.*
      * Die vier durch Dezimalpunkte getrennten Werte der IP werden binär in einen aus   *
      * vier Bytes bestehenden long-Wert gepackt.                                        *
      * Je ein Byte enthält so den dazugehörenden Wert der IP im Binärformat.            *
      * Ist z.B. die eingegebene IP 255.255.254.0, sieht die Aufteilung im long so aus:  *
      * Byte 1: 255                                                                      *
      * Byte 2: 255                                                                      *
      * Byte 3: 254                                                                      *
      * Byte 4: 0                                                                        *
      ***********************************************************************************/
```

In weiterer Folge wird also, wenn ich das richtig verstanden habe, die Methode longAsIpStr dazu programmiert, um da drin die eigentliche Berechnung der möglichen IPs vorzunehmen. Ich muss jetzt also die Subnetzmaske herausfinden (was bei dieser Hausaufgabe zwar kaum nötig wäre, da diese ja sowieso vom Lehrer eingegeben wird, aber wenn ich die Klasse für andere Programme hernehme, wird es sicher nötig werden), dann den Hostteil vom Netzwerkteil unterscheiden, und in weiterer Folge die Anzahl der möglichen IP-Adressen ausrechnen?

Auf alle Fälle schon mal ein riesengroßes Danke für deine Hilfe! :applaus:


----------



## nillehammer (24. Okt 2011)

Ich habe die Erklärung etwas geändert. Hab mir aber bei der Formatierung keine Mühe gegeben ;-))
[Java]
/***********************************************************************************
      * ipStrAsLong: Methode um eine IP-Adresse von einem String in einen long zu packen.*
      * Die vier durch Punkte getrennten Werte der IP (die vier Bytes) werden werden durch parsing ermittelt und dann mit Hilfe des binären left-Shift Operators an die richtige Position eines longs geschoben *
      * Die vier letzten Bytes des long enthalten so den dazugehörenden Wert der IP
      * Ist z.B. die eingegebene IP 255.255.254.0, sieht die Aufteilung im long so aus:  *
      * Byte 1 bis 4: Nicht benutzt und deswegen mit 0en belegt
      * Byte 5: 255                                                                      *
      * Byte 6: 255                                                                      *
      * Byte 7: 254                                                                      *
      * Byte 8: 0                                                                        *
Ein long (wie jeder andere Zahlentyp bei Java auch) kann sowohl dezimal als auch binär interpretiert werden, je nachdem, was benötigt wird. Eine Umrechnung ist nicht erforderlich
      Es wird ein long statt eines int verwendet, weil eine IP-Adresse vorzeichenlos ist. In einem int wird das erste bit aber als Vorzeichen interpretiert (Stichwort: Zweier-Komplement). Dies kann bei Berechnungen und dem Sortieren von Werten zu merkwürdigen Effekten führen.
***********************************************************************************/
[/Java]



> In weiterer Folge wird also, wenn ich das richtig verstanden habe, die Methode longAsIpStr dazu programmiert, um da drin die eigentliche Berechnung der möglichen IPs vorzunehmen.


Nein, das ist die "Spiegel-Methode" für ipStrAsLong. Die brauchen wir für die Ausgabe. Wenn das beides steht, machen wir den Rest. Das ist aber dann nach der Umfangreichen Vorbereitung durch die beiden Methoden ein Kinderspiel und in zwei bis drei Zeilen abzuhandeln.



> (Bits herumgeschoben habe ich vorher überhaupt noch nie.


Ich ehrlich gesagt auch nicht. Außer diesem Anwendungsfall hier ist mir vorher noch nichts begegnet, wo man das sinnvoll einsetzen könnte. Man kann Bit-Shifting zwar benutzen, um performant ganze Zahlen mit 2 zu multiplizieren/ durch 2 zu dividieren. Aber das verschleiert eher die Intention des Codes und ich würde mal vermuten, dass Multiplikationen unter der Haube genau dazu optimiert werden.


----------



## Mampf (25. Okt 2011)

Toll, danke! Damit wäre der erste Teil jetzt fertig... Allerdings verwirrt mich Punkt 1 bei der Methode longAsIpStr etwas, also: 
	
	
	
	





```
-Finde den long-Wert, dessen 8 letzte Bits aus 1en bestehen und sonst nur 0en. Das ist Deine Bitmaske
```
.

Wir haben ja eigentlich nur einen long, nämlich den, der bei ipStrAsLong als Ergebnis rauskommt. Ist das jetzt dann schon die Subnetzmaske, also muss ich bloß dieses Ergebnis an longAsIpStr weiterleiten? Oder muss ich da vorher irgendwie binär vergleichen? Falls ja, würde ich hier bitte wieder um eine Erkärung bitten, da ich aus der Bitwise Operators Website für diesen Verwendungszweck nicht wirklich etwas herausfinden kann.


----------



## nillehammer (25. Okt 2011)

> Oder muss ich da vorher irgendwie binär vergleichen?


Ja, das ist richtig. Wir haben ja jetzt einen long, in dessen letzten vier Bytes der Wert steckt. Diese vier Bytes müssen wir jetzt *einzeln* wieder herausholen. Dafür machen wir uns die einfachen Binäroperationen zu Nutze. Zur Erinnerung die Ergebnisse bei logischen Und-Verknüpfungen:
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
Wenn wir einen long, bei dem alle Bits bis auf die letzten 8 "0" sind, per Und mit unserem long verknüpfen, sorgen wir zuverlässig dafür, dass die ersten 7 Bytes unseres longs genullt werden und nur der Wert im letzten Byte übrig bleibt. Das ist genau der, den wir uns merken wollen. Dann schieben wir in unserem long 8 Bit nach rechts und wiederholen den Vorgang.

Grundsätzlich arbeiten wir hier mit Bitmasken. Mit der richtigen Wahl einer Bitmaske und der geeigneten Verknüpfung (und, oder, exclusiv-oder) kann man ganz tolle Sachen machen (bestimmte Bits ausnullen, bestimmte Bits finden etc.) Zum besseren Verständnis, was wir hier machen, ist folgender Artikel von Wikipedia zu empfehlen: Bitmaske ? Wikipedia
Das brauchen wir auch später noch für die Methode, in der wir die Subnetze berechnen.

Und, wie Du vielleicht schon bemerkt hast, steckt das Wort "maske" sowohl im "Bitmaske" als auch im Wort "Subnetzmaske". Das ist kein Zufall, sondern Absicht. Es ist nämlich so, dass die Subnetzmaske eine Bitmaske für IPs ist.


----------



## Mampf (25. Okt 2011)

Das heißt also, dieser zweite long, mit dem verknüpft wird müsste dann die Zahl 255 enthalten? (weil ja 255 11111111 in Binärform ist)


----------



## nillehammer (25. Okt 2011)

> Das heißt also, dieser zweite long, mit dem verknüpft wird müsste dann die Zahl 255 enthalten? (weil ja 255 11111111 in Binärform ist)


Korrekt!


----------



## Mampf (25. Okt 2011)

Jetzt habe ich wieder ein etwas lächerliches Problem... wie fülle ich ein Array am besten von hinten an?

Von vorne müsste der Code ja so aussehen:

```
for(int i = 0; i < intArray.length; i++) {
            intArray[i] = value&temp; //value ist der eingelesene long, temp 255.
            //shift
        }
```


----------



## nillehammer (25. Okt 2011)

Du musst in der for-Schleife dekrementieren, sprich:
- Der Initialwert ist die Arraylänge minus 1
- Der Abbruchwert ist 0 (und >= statt <=)
- Du machst i-- statt i++

//Edit: Habe gerade noch etwas korrigiert.


----------



## Mampf (25. Okt 2011)

OK... die Arrayfüllung müsste dann also so funktionieren:


```
for(int i = intArray.length; i >= 0; i--) { 
            intArray[i] = value&temp; // alle Werte bis auf das letzte Byte in value 0 setzen und von hinten die Positionen des Arrays füllen
            value = value >> 8; //8 bits nach rechts shiften
            
        }
```


----------



## nillehammer (25. Okt 2011)

Fast, in Deinem Code stecken noch zwei Fehler. Einer wird Dir schon beim Kompilieren auffallen. Der andere erst zur Laufzeit. Programmier den Code mal in einer IDE runter und versuch, ob Du sie selbst findest und lösen kannst. Ansonsten frag.


----------



## Mampf (25. Okt 2011)

Also die IDE gibt mir bei 
	
	
	
	





```
intArray[i] = value&temp;
```
 einen "possible loss of precision", da von long zu int konvertiert wird. Gibt es da eine bessere Methode?


----------



## nillehammer (25. Okt 2011)

Erstaunlich, meine IDE gibt mir da einen Compiler-Error... Hmm, da hat sich vielleicht von Java 6 nach Java 7 was geändert. Der "loss of precision" ist übrigens in unserem Fall garnicht gegeben. Das wäre nur ein Problem, wenn in den ersten 4 Bytes des long von 0 verschiedene Werte drinnen stehen würden (sprich, wenn wir Zahlen größer Integer.MAXVALUE hätten), was bei uns ja nicht der Fall ist.

... Moment mal, was ist denn das "temp" bei Dir? Da müsste doch eigentlich die (konstante) Bitmaskte hin. Kannst Du mal den kompletten Code der Methode "longAsIpStr" zur Kontrolle posten (was Du halt bis jetzt schon hast)?


----------



## Mampf (25. Okt 2011)

Meine Methode sieht einstweilen so aus:


```
public static final String longAsIpString (final long value) {
        
        long temp = 255; //long zum Verknüpfen.
        int[] intArray = new int[4]; //Array zum Speichern der Werte.
        
        for(int i = intArray.length; i >= 0; i--) { 
            intArray[i] = value&temp; // alle Werte bis auf das letzte Byte in value 0 setzen und von hinten die Positionen des Arrays füllen
            value = value >> 8; //8 bits nach rechts shiften
            
        }
        
        String resultStr= ""; //einstweilen noch leer
        
        return resultStr;
    }
```


----------



## nillehammer (25. Okt 2011)

Ahh ok, sieht soweit gut aus. Auch hier würde ich "temp" nicht als Variable innerhalb der Methode deklarieren, sondern als Konstante (public static final long) in der Klasse. Und als Namen schlage ich statt "temp" sowas wie "BITMASK" oder "EIGHT_BITS" oder so vor. Ist etwas sprechender.

Lass den Code mal testweise laufen. Dann wirst Du noch den Laufzeitfehler finden. Lies Dir die Message der Exception genau druch, dann solltest Du auch drauf kommen, was falsch ist.


----------



## Mampf (25. Okt 2011)

Der Laufzeitfehler:

```
Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - possible loss of precision
  required: int
  found:    long
	at Uebung2.IpConverter.longAsIpString(IpConverter.java:51)
	at Uebung2.UI.main(UI.java:25)
Java Result: 1
```

Also stößt dem Compiler die long zu int-Umwandlung sauer auf, wenn ich diese Message richtig interpretiere?


----------



## nillehammer (25. Okt 2011)

Das sieht für mich danach aus, dass Du unter Java 7 entwickelst und kompilierst. Dann aber als Laufzeitumgebung Java 6 benutzt. Falls du Dein Programm aus der IDE heraus startest, schau mal, dass dort alles auf Java 7 eingestellt ist. Falls Du Dein Programm von der Kommandozeile aus startest, schau, dass der PATH auf das Java 7 zeigt oder gib den Pfad zu der Java 7 Version von java explizit an. Deinsalliere ggf. Dein Java 6, wenn Du es nicht mehr brauchst.

Ansonsten mach einfach einen expliziten cast nach int (ein sog. Downcast).

Das war eigentlich nicht der Laufzeitfehler, auf den ich hinaus wollte. Der kommt dann als nächstes .

P.S. "Uebung2": falls das ein package name ist, schreibe ihn bitte klein. So ist die Konvention.


----------



## Mampf (25. Okt 2011)

Aha...

```
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
	at Uebung2.IpConverter.longAsIpString(IpConverter.java:51)
	at Uebung2.UI.main(UI.java:25)
Java Result: 1
```
ArrayIndexOutOfBounds heißt, dass ich auf eine Stelle im Array hinzeige die es nicht gibt... also habe ich vergessen von intArray.length 1 abzuziehen


----------



## nillehammer (25. Okt 2011)

Genau! Jetzt fehlt noch das Zusammenbauen des Ausgabestrings. Wenn Du damit fertig bist, bitte wieder den Code der kompletten Methode posten.


----------



## Mampf (25. Okt 2011)

Der Code:

```
public static final String longAsIpString (final long value) {
        
        int[] intArray = new int[4]; //Array zum Speichern der Werte.
        String resultStr= ""; //String, in dem das Ergebnis gespeichert wird.
        
        for(int i = intArray.length -1; i >= 0; i--) { 
            intArray[i] = (int) (value&BITMASK); // alle Werte bis auf das letzte Byte in value 0 setzen und von hinten die Positionen des Arrays füllen (downcast nach int)
            value = value >> 8; //8 bits nach rechts shiften
            
        }
        
        for(int i = 0; i < intArray.length; i++) {
            resultStr = resultStr + intArray[i];
            
        }
        
        
        return resultStr;
    }
```

Allerdings bekomme ich jetzt immer folgende Errormeldung, die offenbar etwas mit 
	
	
	
	





```
value = value >> 8;
```
 zu tun hat:

```
Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - final parameter value may not be assigned
	at Uebung2.IpConverter.longAsIpString(IpConverter.java:53)
	at Uebung2.UI.main(UI.java:25)
Java Result: 1
```


----------



## nillehammer (25. Okt 2011)

```
Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - final parameter value may not be assigned
```
Nein, das war wieder mein Fehler. Nimm das final vor dem Parameter der Methode weg. Und beim Zusammenbauen des Strings hast Du die Punkte vergessen.


----------



## Mampf (25. Okt 2011)

Die Methode funktioniert!

Code:

```
public static final String longAsIpStr (long value) {
        
        int[] intArray = new int[4]; //Array zum Speichern der Werte.
        String resultStr= ""; //String, in dem das Ergebnis gespeichert wird.
        
        for(int i = intArray.length -1; i >= 0; i--) { 
            intArray[i] = (int) (value&BITMASK); // alle Werte bis auf das letzte Byte in value 0 setzen und von hinten die Positionen des Arrays füllen (downcast nach int)
            value = value >> 8; //8 bits nach rechts shiften
            
        }
        
        for(int i = 0; i < intArray.length; i++) { //Aus den ints im Array den String zusammenbauen.
            
            if(i == (intArray.length -1)) {
                
                resultStr = (resultStr + intArray[i]);
                
            }else {
                
                resultStr = (resultStr + intArray[i] + ".");
                
            }  
        }
          
        return resultStr;
    }
```

Also, wenn ich diese Methode jetzt erklären muss, ist sie eigentlich dazu da, um zuerst einmal aus der eingegebenen IP die Subnetzmaske herauszufiltern -> darum werden die bits herumgeschubst. Heißt das jetzt, dass in jeder IP eine Subnetzmaske enthalten ist?
Dann wird die Subnetzmaske von hinten nach vorne ins Array geschrieben, aus diesem in weiterer Folge der Ausgabestring gebaut.
Und noch etwas ist mir nicht ganz klar: warum machen wir die beiden Methoden eigentlich final?


----------



## nillehammer (25. Okt 2011)

> Also, wenn ich diese Methode jetzt erklären muss, ist sie eigentlich dazu da, um zuerst einmal aus der eingegebenen IP die Subnetzmaske herauszufiltern -> darum werden die bits herumgeschubst. Heißt das jetzt, dass in jeder IP eine Subnetzmaske enthalten ist?


Nein, diese Methode ist dazu da, eine als long gespeicherte IP oder Subnetzmaske in einen Ausgabestring zu verwandeln. Wir haben mit den beiden bisherigen Methoden "nur" die Konversion zwischen String und long gebastelt. Hat Dein Lehrer ja gesagt, dass Du das machen sollst.

Die Methode für das von Dir ursprünglich angefrage Berechnen von IP-Subnetzen inkl. maximaler Adressen und dem von-bis-Bereich kommt jetzt. Sie wird die Funktionen der beiden Methoden nutzen. Dazu ist zunächst wichtig zu verstehen, was eine Netzmaske eigentlich macht (wie also die Aufteilung in Netzteil und Hostteil unter der Haube funktioniert). Dazu kann ich diesen Artikel hier sehr empfehlen: Netzmaske ? Wikipedia
Da ist auch schon erklärt, was die kommende Methode machen muss.

Folgende Ausgaben würde ich von der Methode erwarten:
Eingegebene Werte: xxxx
Netznummer: xxxx
Netzmaske: xxxxx
Anzahl möglicher IPs:
Bereich von bis: xxx

evtl noch:
Broadcastadresse: xxxx

Überlege zunächst, wie Du die Ausgabe machen möchtest:
- Einfach als Output auf der Console?
- Komplett als ein Text auf einem Textfeld?
- Die verschiedenen Werte vielleicht in einer Tabelle?
Davon hängt ab, wie der return-Value der Metode aussehen muss.

Dann überlege, welche Werte Du als Eingabeparameter für Deine Methode brauchst. Das sind dann die Parameter der Methode. Als Namen würde ich "outputSubnetData" vorschlagen. Auch wieder public static final.



> warum machen wir die beiden Methoden eigentlich final?


Gute Frage, das ist eine Frage der Designphilosophie. Können wir die Antwort evtl. zurückstellen, bis die Klasse komplett fertig ist? Du hast ja morgen Abgabetermin oder?


> Heißt das jetzt, dass in jeder IP eine Subnetzmaske enthalten ist?


Nochmal speziell die Antwort auf diese Frage: Nein, wenn Du Dich an die Netzwerkkonfiguration Deines Rechners erinnerst (es sei denn Du benutzt DHCP), dann müssen immer die IP und eine Subnetzmaske zusammen eingebeben werden. Wir können für beides die bisherigen Methoden benutzen. Also keine Angst, sehr viel Arbeit ist es nicht mehr!


----------



## nillehammer (25. Okt 2011)

Ich geh mal kurz Kippen holen... bis gleich.


----------



## Mampf (25. Okt 2011)

Also, Abgabetermin ist morgen in einer Woche... ich würde vorschlagen wir machen dann morgen weiter, hab gestern nicht gerade viel Schlaf bekommen  Danke auf alle Fälle bis hierher.


----------



## nillehammer (25. Okt 2011)

> warum machen wir die beiden Methoden eigentlich final?


Ich habe nochmal über die Frage nachgedacht. Und ich ärgere mich, dass ich das nicht schon früher gemacht habe.  *Final for statischen Methoden ist völlig überflüssig.* Danke für den Hinweis.



> Ich würde vorschlagen wir machen dann morgen weiter, hab gestern nicht gerade viel Schlaf bekommen


Alles klar, bis morgen.


----------



## Mampf (26. Okt 2011)

So, die Dokumentation für longAsIpStr hätte ich jetzt auch mal fertig.


```
/*************************************************************************************************************    
      *longAsIpStr: Umgekehrte Methode von IpStrAsLong. Aus dem vorher gepackten long (der IP), werden zunächst    *
      * die Zahlenwerte ausgelesen und in das Array intArray gepackt. Der long wird von hinten nach vorne          *
      * durchgearbeitet, daher auch das Array von hinten gefüllt. Dies geschieht, indem zunächst alles bis auf das *
      * letzte Byte des longs 0 gesetzt wird. So bleibt die gesuchte Zahl übrig und wird ins Array geschrieben.    *
      * Dann wird ein Byte nach rechts geshiftet, und das vorletzte Byte wird an die vorletzte Stelle des Arrays   *
      * geschrieben. Der Shift- und Schreibvorgang geschieht dann noch zweimal, bis alle vier Zahlenwerte der IP   *
      * im Array stehen.                                                                                           *
      * In weiterer Folge wird das Array von vorne nach hinten durchgegangen und die Werte in den Ausgabestring    *
      * geschrieben, wobei Dezimalpunkte hinzugefügt werden, damit wieder eine IP entsteht.                        *
      *************************************************************************************************************/
```

Für die Outputmethode habe ich ziemlich klare Vorgaben, es soll wirklich genauso aussehen, wie ich es ziemlich am Anfang des Threads schon gepostet habe. 

Also: 
	
	
	
	





```
Geben Sie die Subnetzmaske des gewünschten IP-Pools ein: 255.255.255.240
Geben Sie die IP-Adresse des gewünschten IP-Pools ein: 113.8.66.42
Ausgabe: Der gesuchte IP-Pool lautet 113.8.66.33 bis 113.8.66.46.
```

Ich hätte den ganzen Ein- und Ausgabeteil eigentlich schon als Grundgerüst programmiert:


```
package uebung2;


import iO.IO;




public class UI {


    public static void main(String[] args) {
        
        String netmask, ip;
        char repeat;
        
        do {
        
        IO.write("Geben Sie die Subnetmaske des gewünschten IP-Pools ein: ");
        netmask = IO.readLine();
        
        IO.write("Geben Sie die IP-Adresse des gewünschten IP-Pools ein: ");
        ip = IO.readLine();
        
        
        
        
        IO.writeLn("Der gesuchte IP-Pool lautet: ");
        
        IO.write("Noch eine Umwandlung? [j/n]: ");
        repeat = IO.read();
        IO.readLn();
        
        }while((repeat == 'j') || (repeat == 'J'));
        
    }
}
```

Also für die Hausaufgabe soll wirklich nur der IP-Adressenbereich von - bis programmiert werden, mich würde es allerdings dann zusätzlich schon auch interessieren, wie z.B. die Netznummer berechnet wird.

Ahja, und danke für den Hinweis, dass Packages klein geschrieben werden, das haben wir in der Schule so nicht gelernt


----------



## nillehammer (26. Okt 2011)

Die Dokumentation der Methode "longAsIpStr" ist in Ordnung. Da gibt es nichts mehr zu verbessern.

Entsprechend Deiner Vorgaben für die output-Methode (output auf Console) und der geforderten Eingaben ist auch schon die Frage nach return-Value und Methodenparametern für die Methode "outputSubnetValues" beantwortet.



> Also für die Hausaufgabe soll wirklich nur der IP-Adressenbereich von - bis programmiert werden, mich würde es allerdings dann zusätzlich schon auch interessieren, wie z.B. die Netznummer berechnet wird.


Dazu lies Dir bitte erst noch den Wikipediaartikel über Netzmaske durch. Zur Erinnerung nochmal der Link: Netzmaske ? Wikipedia
Da steht es fast schon drinnen, was Du in der Methode machen musst, um die gewünschten Werte zu ermitteln.



> Ahja, und danke für den Hinweis, dass Packages klein geschrieben werden, das haben wir in der Schule so nicht gelernt


Du bist noch ein Schüler?!? Ich hatte eher den Eindruck, mit einem Studenten zu kommunizieren, Respekt!


----------



## Mampf (26. Okt 2011)

Also wenn ich jetzt richtig gelesen habe, bekomme ich den Netzwerkteil der Subnetzmaske raus, wenn ich diese mit & mit der IP verknüpfe.
Für den Hostteil brauche ich dann AND NOT, also Subnetzmaske&~IP.

Stimmt das so?



> Du bist noch ein Schüler?!? Ich hatte eher den Eindruck, mit einem Studenten zu kommunizieren, Respekt!


Danke! Naja, ich bin "noch" Schüler, aber nicht mehr lange, weil in ein paar Monaten die Matura ansteht  (bin aus Österreich)


----------



## nillehammer (26. Okt 2011)

> Also wenn ich jetzt richtig gelesen habe, bekomme ich den Netzwerkteil der Subnetzmaske raus, wenn ich diese mit & mit der IP verknüpfe.


Fast richtig. Du bekommst den Netzwerkteil der *IP-Adresse* raus, wenn Du diese mit der Subnetzmaske mit & verknüpfst (meintest Du bestimt auch). Das Praktische ist, dass der resultierende Wert auch gleichzeitig die niedrigste Adresse des betreffenden Subnetzes ist. Diese ist per Definition die Subnetznummer. Die Subnetznummer selbst kann nicht an Hosts vergeben werden. Die niedrigste an Hosts vergebbare Adresse ist Subnetznummer + 1.



> Für den Hostteil brauche ich dann AND NOT, also Subnetzmaske&~IP.


Stimmt auch fast. Das Statement muss auch hier mit der IP beginnen, also "IP&~Subnetzmaske" Der Hostteil ist für die Aufgabenstellung aber nicht interessant. Was wir brauchen, ist niedrigste Adresse (siehe oben), die mögliche Anzahl von IPs (siehe mein allererster Post), sowie das Wissen, dass die niedrigste Adresse nicht an Hosts vergeben werden kann, weil sie die Netznummer ist und die höchste nicht, weil sie die Broadcastadresse ist.


----------



## nillehammer (26. Okt 2011)

> Danke! Naja, ich bin "noch" Schüler, aber nicht mehr lange, weil in ein paar Monaten die Matura ansteht (bin aus Österreich)


Cool, war vor zwei Wochen in Wien. Hat mir sehr gut fefallen. Das Abi heißt in Österreich Matura, Jura heißt in Österreich Jus und die Schüler sind wie Studenten. Ich wusste es schon immer: Österreich ist die bessere Version von Deutschland (*wegduck*).


----------



## Mampf (26. Okt 2011)

Ok, der Netzwerkteil als String kommt raus, wenn ich 


```
String netpart = longAsIpStr(( ipStrAsLong(netmask) & ipStrAsLong(ip) ));
```
 ausführe, nachdem wir allerdings noch mit den Wertten rechnen wollen, denke ich, dass ich netpart zuerst nur als long ausgeben sollte, und die Konvertierung in einen string erst vornehmen sollte, wenn alle Berechnungen abgeschlossen sind.


----------



## nillehammer (26. Okt 2011)

Ja, sehe ich auch so.
- Wandele die Stings zunächst in longs für ip und netzmaske um und speichere diese in lokalen Variablen
- Rechne mit der invertierten Netzwerkmaske die Anzahl möglicher IPs aus und speichere auch diese in einer lokalen Variablen
- Mit diesen drei Werten mache dann die Ausgaben.

Und noch ein Hinweis: Nimm bei den Berechnungen die ip immer nach vorne. Bei einfachen Verknüpfungen ist das zwar egal. Aber so hält man sich gleich an ein einheitliches Verfahren.


----------



## Mampf (26. Okt 2011)

OK, der Code für die niedrigste IP funktioniert schonmal:

```
public static String outputSubnetValue(String ip, String netmask) {
    
        String resultStr = "";
        
        long ipLong = ipStrAsLong(ip);
        long netmaskLong = ipStrAsLong(netmask);
        long netpart = ipLong&netmaskLong; //IP mit Netzmaske verknüpfen, hiermit wird der Netzwerkteil der IP bestimmt
        
        netpart = netpart + 1; //1 dazuzählen, weil der Netzwerkteil = niedrigste Nummer ist, und diese nicht vergeben werden darf. 
        
        
        return resultStr;
        
    }
```

Aber wie komme ich jetzt zu der höchsten möglichen Nummer?



> Ich wusste es schon immer: Österreich ist die bessere Version von Deutschland


Naja, das würd ich jetzt so nicht sagen, ich bin sogar stark am Überlegen, ob ich nach DE studieren gehe


----------



## nillehammer (26. Okt 2011)

[Java]netpart = netpart + 1; //1 dazuzählen, weil der Netzwerkteil = niedrigste Nummer ist, und diese nicht vergeben werden darf. [/Java]
Lass bitte hier das +1 weg. Du brauchst den unverfälschten Wert noch zum Rechnen. Mach die Addition/Subtraktion entweder erst bei der Ausgabe oder merk Dir die Werte in weiteren Variablen.



> Aber wie komme ich jetzt zu der höchsten möglichen Nummer?


An die höchste mögliche Nummer kommst Du, indem Du netpart + mögliche Anzahl IPs machst (Deswegen auch die Bitte, netpart nicht mit + 1 zu verfälschen). Die mögliche Anzahl von IPs hängt direkt mit der Netzmaske zusammen und zwar wie folgt:
Eine 0 am Ende = 2 hoch 1 = 2 IPs (da niedrigste die Netznummer und höchste der Broadcast keine mehr frei für Hosts, also ungültig)
Zwei 0 am Ende = 2 hoch 2 = 4 IPs
Drei 0 am Ende = 2 hoch 3 = 8 IPs
usw.
Du könntest also die Nullen am Ende zählen und das Ergebnis hoch zwei nehmen. Die Klasse Long bietet fürs Zählen eine entsprechende Methode an.

Es gibt aber noch eine einfachere Möglichkeit. Hier machst Du Dir die Darstellung negativer Zahlen mit Hilfe des Zweier-Komplements in Java zu Nutze. Caste mal Deine Netzwerkmaskenwerte nach int. Du wirst ein überraschenes Ergebnis feststellen...


----------



## Mampf (26. Okt 2011)

Also, wenn meine Netzmaske 255.255.255.0 ist, kommt mir als long 4294967040 raus, als int -256. Ist das dieses Zweierkomplement?


----------



## nillehammer (26. Okt 2011)

Genau, Du schneidest mit dem Cast nach int die führenden Nullen ab. Was übrig bleibt ist die reine Netzwerkmaske, die ja immer mit 1en beginnt und dann irgendwann mittendrin auf 0en wechselt. Eine Bitfolge (egal, ob in long, int, short oder byte), deren erstes Bit 1 ist, wird von Java als negativ angesehen. Was nun noch interessant ist, ist die Art und Weise, wie Java dann den Betrag speichert. Das tut es mittels Zweier-Komplement. Das ist insofern Praktisch, als wir so genau unsere gesuchte Zahl erhalten (eben nur mit dem negativen Vorzeichen). Das funktioniert, weil Netzmasken wie gesagt immer mit 1en beginnen. Die einzige Maske, wo das nicht funktioniert ist "0.0.0.0". Aber die würde ich (außer bei der Angabe von Routen) sowieso als ungültig ansehen und darum ist es nicht schlimm.


----------



## Mampf (26. Okt 2011)

Also, die Zahl die bei negativer Netzmaske rauskommt ist die maximale letzte Stelle der IP? Aber ist nicht der maximal mögliche Wert generell 255?

Außerdem habe ich zwecks besserem Verständnis noch eine kleine Frage zu longAsIpStr, und zwar da, wo wir das Array füllen.
Wenn ich das jetzt richtig verstanden haben, ist die Vorgangsweise so, dass wir zunächst die letzten 8 bits des long hernehmen, in die letzte Stelle des Arrays schreiben, und dann, indem wir 8 bits nach rechts shiften, die letzten 8 bits rauskicken und die vorletzten 8 an die Stelle der letzten setzen (und das dann noch zwei mal). Ist das so korrekt?


----------



## nillehammer (26. Okt 2011)

> Also, die Zahl die bei negativer Netzmaske rauskommt ist die maximale letzte Stelle der IP?


Nein, das ist die maximale Anzahl der IPs in dem jeweiligen Subnetz. Die maximale letzte Stelle ist die Summe von niedgrigster IP plus der Anzahl.


> Aber ist nicht der maximal mögliche Wert generell 255?


Nein. Bei den "Standard"-Größen (z.B. 255.255.255.0) ist es *zufällig* so. Nimm aber mal folgendes Netz: 10.1.2.0/255.255.255.128 Da ist die höchste Adresse die .127



> Ist das so korrekt?


Ja absolut.


----------



## Mampf (26. Okt 2011)

Also jetzt weiß ich dann schon mal die erste IP + die Möglichkeiten. Das heißt theoretisch könnte ich jetzt den String mit der niedrigsten IP-Nummer hernehmen, die letzte Nummer in einen int verwandeln, dann die Möglichkeiten dazurechnen, und anschließend die ersten drei Werte des Strings hernehmen und als vierten die letzte Nummer + Möglichkeiten nehmen.

Wenn ich das jetzt so abtippe kommt mir das aber etwas umständlich vor... gibt es da vielleicht eine elegantere Methode?


----------



## nillehammer (26. Okt 2011)

> Also jetzt weiß ich dann schon mal die erste IP + die Möglichkeiten. Das heißt theoretisch könnte ich jetzt den String mit der niedrigsten IP-Nummer hernehmen, die letzte Nummer in einen int verwandeln, dann die Möglichkeiten dazurechnen, und anschließend die ersten drei Werte des Strings hernehmen und als vierten die letzte Nummer + Möglichkeiten nehmen.


Nein, Du must die niedrigste IP als long wert nehmen, dazu die Anzahl addieren und dann erst mittels longAsIpStr die Ausgabe erzeugen.


----------



## Mampf (26. Okt 2011)

Also irgendwas funktioniert da nicht richtig...

[Java]public static String outputSubnetValue(String ip, String netmask) {

        String resultStr = "";

        long ipLong = ipStrAsLong(ip);
        long netmaskLong = ipStrAsLong(netmask);
        long netpart = ipLong&netmaskLong; //IP mit Netzmaske verknüpfen, hiermit wird der Netzwerkteil der IP bestimmt

        long lowest = netpart + 1; //1 dazuzählen, weil der Netzwerkteil = niedrigste Nummer ist, und diese nicht vergeben werden darf. 
        int netmaskInt = (int) netmaskLong; //durch den downcast der netmask zu int wird die negative Anzahl der Möglichkeiten gefunden (Zweierkomplement)
        netmaskInt = Math.abs(netmaskInt); //Anzahl positiv machen
        long highest = netpart + netmaskInt;


        resultStr=(longAsIpStr(lowest) + " bis " + longAsIpStr(highest));

        return resultStr;

    }[/Java]

Hab jetzt schon herumprobiert, aber irgendetwas läuft da schief.


----------



## nillehammer (26. Okt 2011)

Sieht eigentlich gut aus. Ich würde nur zwei Zeilen ändern. Zeile 9 löschen und in Zeile 15:
[Java]
resultStr=(longAsIpStr(netpart +1 ) + " bis " + longAsIpStr(highest -1));
[/Java]
So müsste es passen. Was bekommst Du denn für eine Ausgabe?


----------



## nillehammer (26. Okt 2011)

So, ich habe Deinen Code gerade genommen und meine Änderungen eingebaut. So scheint er zu funktionieren. Wo gefällt Dir was nicht?


----------



## nillehammer (26. Okt 2011)

So nochmal ich. Ein kleiner Fehler ist doch noch drinnen. Er hat statt der höchst möglichen Host-IP immer die Broadcastadresse ausgegeben.

Dadurch, dass wir nach int gecastet haben, erhalten wir zwar die Anzahl möglicher IPs, aber dazuaddieren dürfen wir nur immer eins weniger bzw wir müssen für die Angabe der höchst möglichen Host-IP zwei abziehen. Mit der folgenden Zeile ist dann alles korrekt:
[Java]
resultStr=(longAsIpStr(netpart + 1) + " bis " + longAsIpStr(highest -2));
[/Java]


----------



## Mampf (26. Okt 2011)

Jap, so läuft's 

Das Problem war, dass irgendetwas bei der Berechnung von highest schief lief und somit der dritte Wert der IP geändert wurde.
Da war dann z.B IP von 192.168.1.1 bis 192.168.2.1 (was so natürlich nicht stimmt).

Das heißt, jetzt noch die letzte Methode ordentlich kommentieren und dann ist das Programm fertig!

Ich möchte mich nochmal ganz herzlich für deine Hilfe und Geduld bedanken, das war echt toll 
Außerdem war dieses Programm eine der für mich lehrreichsten Erfahrungen in Java überhaupt. Danke!


----------



## nillehammer (26. Okt 2011)

> Da war dann z.B IP von 192.168.1.1 bis 192.168.2.1 (was so natürlich nicht stimmt).


Stimmt, so eine Range ist Quatsch. Bei "großen" Netzmasken kann es aber schon Ranges geben, wo sich die dritte oder sogar die zweite Stelle der IP ändern. Z.B. bei dieser Kombination: 192.168.0.0/255.255.128.0


> Ich möchte mich nochmal ganz herzlich für deine Hilfe und Geduld bedanken, das war echt toll
> Außerdem war dieses Programm eine der für mich lehrreichsten Erfahrungen in Java überhaupt. Danke!


Gern geschehen. Hat mir sehr viel Spaß gemacht. Und ich hab sogar auch was dabei gelernt (nämlich das final vor statischen Methoden Blödsinn ist.)


----------



## Mampf (26. Okt 2011)

> Gern geschehen. Hat mir sehr viel Spaß gemacht.


Danke, mir ebenfalls! In letzter Zeit hat zugegebenermaßen mein Enthusiasmus fürs Programmieren etwas nachgelassen, aber durch dieses Programm wieder einen dicken Boost bekommen ^^


----------



## nillehammer (26. Okt 2011)

> ...aber durch dieses Programm wieder einen dicken Boost bekommen ^^


Super, sei bitte noch so nett, wenn Du mit den Kommentaren fertig bist, dass Du dann noch mal den Code der kompletten Klasse postest. Dann kann man das Werk nochmal in seiner ganzen Pracht bewundern.:toll:


----------



## Mampf (26. Okt 2011)

Gerne:


```
package uebung2;

public final class IpConverter {
//Author: Paul W******
    
    private static final String SPLIT_EXP = "\\."; //Diese Konstante wird später benötigt, um den String zu splitten.
    public static final long BITMASK = 255; //Die Bitmaske wird später zum Verknüpfen gebraucht.
   
      /****************************************************************************************************
      * ipStrAsLong: Methode um eine IP-Adresse von einem String in einen long zu packen.                 *
      * Die vier durch Punkte getrennten Werte der IP (die vier Bytes) werden durch parsing               *
      * ermittelt und dann mit Hilfe des binären left-Shift Operators an die richtige Position            *
      * eines longs geschoben                                                                             *
      * Die vier letzten Bytes des long enthalten so den dazugehörenden Wert der IP.                      *
      * Ist z.B. die eingegebene IP 255.255.254.0, sieht die Aufteilung im long so aus:                   *
      * Byte 1 bis 4: Nicht benutzt und deswegen mit 0en belegt                                           *
      * Byte 5: 255                                                                                       *
      * Byte 6: 255                                                                                       *
      * Byte 7: 254                                                                                       *
      * Byte 8: 0                                                                                         *
      * Ein long (wie jeder andere Zahlentyp bei Java auch) kann sowohl dezimal als auch binär            *
      * interpretiert werden, je nachdem, was benötigt wird. Eine Umrechnung ist nicht erforderlich       *
      * Es wird ein long statt eines int verwendet, weil eine IP-Adresse vorzeichenlos ist.               *
      * In einem int wird das erste bit aber als Vorzeichen interpretiert (Stichwort: Zweier-Komplement). *
      *  Dies kann bei Berechnungen und dem Sortieren von Werten zu merkwürdigen Effekten führen.         *
      ****************************************************************************************************/
    public static long ipStrAsLong (final String ipStr) {
    
        long result = 0;
        final String[] strArray = ipStr.split(SPLIT_EXP); //String-Array erzeugen, String bei den Punkten splitten und ins Array schreiben
    
        for(int i = 0; i < strArray.length; i++) { //Array durchgehen
            int temp = Integer.parseInt(strArray[i]);
            result = result|temp; //long result bitweise mit int temp verknuepfen
            
            if(i != (strArray.length -1)) { //wenn nicht am Ende des Arrays angelangt, letzten Wert 8 Bits nach links shiften.
                result = result << 8;
                
            }
        }
    
        return result;
    }
      
      /*************************************************************************************************************    
      *longAsIpStr: Umgekehrte Methode von IpStrAsLong. Aus dem vorher gepackten long (der IP), werden zunächst    *
      * die Zahlenwerte ausgelesen und in das Array intArray gepackt. Der long wird von hinten nach vorne          *
      * durchgearbeitet, daher auch das Array von hinten gefüllt. Dies geschieht, indem zunächst alles bis auf das *
      * letzte Byte des longs 0 gesetzt wird. So bleibt die gesuchte Zahl übrig und wird ins Array geschrieben.    *
      * Dann wird ein Byte nach rechts geshiftet, und das vorletzte Byte wird an die vorletzte Stelle des Arrays   *
      * geschrieben. Der Shift- und Schreibvorgang geschieht dann noch zweimal, bis alle vier Zahlenwerte der IP   *
      * im Array stehen.                                                                                           *
      * In weiterer Folge wird das Array von vorne nach hinten durchgegangen und die Werte in den Ausgabestring    *
      * geschrieben, wobei Dezimalpunkte hinzugefügt werden, damit wieder eine IP entsteht.                        *
      *************************************************************************************************************/
    public static String longAsIpStr (long value) {
        
        int[] intArray = new int[4]; //Array zum Speichern der Werte.
        String resultStr= ""; //String, in dem das Ergebnis gespeichert wird.
        
        for(int i = intArray.length -1; i >= 0; i--) { 
            intArray[i] = (int) (value&BITMASK); // alle Werte bis auf das letzte Byte in value 0 setzen und von hinten die Positionen des Arrays füllen (downcast nach int)
            value = value >> 8; //8 bits nach rechts shiften
            
        }
        
        for(int i = 0; i < intArray.length; i++) { //Aus den ints im Array den String zusammenbauen.
            
            if(i == (intArray.length -1)) {
                
                resultStr = (resultStr + intArray[i]);
                
            }else {
                
                resultStr = (resultStr + intArray[i] + ".");
                
            }  
        }
          
        return resultStr;
    }
    
    /****************************************************************************************************
     * outputSubnetValue: Methode, um die kleinste und größte IP-Adresse aus einer eingegebenen IP      *
     * + Subnetzmaske zu ermitteln. Zunächst werden die beiden Strings mithilfe von ipStrAsLong() in    *
     * longs gepackt. Dann wird die IP mit der Netzmaske binär verknüpft, womit der Netzwerkteil der IP *
     * bestimmt wird. Dieser ist zugleich auch die Subnetznummer, die niedrigste IP ergibt sich aus     *
     * Subnetznummer + 1.                                                                               *
     * Daraufhin wird die Anzahl der möglichen IPs ausgerechnet, indem die Subnetzmaske als int         *
     * gedowncastet wird. Die Anzahl der möglichen IPs + die niedrigste IP ergibt dann die höchste IP +1*
     * , weil die Broadcast-Adresse nicht mitgerechnet werden darf. Die niedrigste und höchste IP werden*
     * schlussendlich in einen String geschrieben und als Rückgabewert zurückgegeben.                   *
     ***************************************************************************************************/
    public static String outputSubnetValue(String ip, String netmask) {
    
        String resultStr = "";
        
        long ipLong = ipStrAsLong(ip);
        long netmaskLong = ipStrAsLong(netmask);
        long netpart = ipLong&netmaskLong; //IP mit Netzmaske verknüpfen, hiermit wird der Netzwerkteil der IP bestimmt
        
        int netmaskInt = (int) netmaskLong; //durch den downcast der netmask zu int wird die negative Anzahl der Möglichkeiten gefunden (Zweierkomplement)
        netmaskInt = Math.abs(netmaskInt); //Anzahl positiv machen
        long highest = netpart + netmaskInt; //höchsten Wert der IP bestimmen, indem die Anzahl der möglichen IPs zur niedrigsten Adresse addiert wird
        
        	
        resultStr=(longAsIpStr(netpart +1 ) + " bis " + longAsIpStr(highest -2)); // die longs werden in Strings umgewandelt -> niedrigste + 1, weil .0 nicht vergeben werden darf
        return resultStr;                                                         //(Fortsetzung) höchste -2, weil Broadcast nicht vergeben werden darf
        
    }
}
```

Die UI:


```
package uebung2;


import iO.IO;




public class UI {


    public static void main(String[] args) {
        
        String netmask, ip;
        char repeat;
        
        do {
        
        IO.write("Geben Sie die Subnetzmaske des gewünschten IP-Pools ein: ");
        netmask = IO.readLine();
        
        IO.write("Geben Sie die IP-Adresse des gewünschten IP-Pools ein: ");
        ip = IO.readLine();
        
        String result = IpConverter.outputSubnetValue(ip, netmask);
        
        
        IO.writeLn("Der gesuchte IP-Pool lautet: " + result);
        
        IO.write("Noch eine Umwandlung? [j/n]: ");
        repeat = IO.read();
        IO.readLn();
        
        }while((repeat == 'j') || (repeat == 'J'));
        
    }
}
```


----------

