IP-Adressenpool berechnen

Mampf

Mitglied
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
Java:
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.
 
N

nillehammer

Gast
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)
 
N

nillehammer

Gast
Nochmal ich.
Der Algorhitmus zum Parsen eines Stings in einen IP-Wert:
Code:
- 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
Code:
-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
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
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.
 
N

nillehammer

Gast
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:
Java:
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.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

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

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

Mampf

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

Code:
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:
Java:
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)
 
N

nillehammer

Gast
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

Mitglied
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
Java:
if(i != (strArray.length - 1) {
  //Shift
}
in der for-Schleife funktionieren.
 
N

nillehammer

Gast
-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?
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
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)
Java:
result = result|temp //result ist der long und temp der int
und im if-Block dann:
Java:
result >> 8

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

nillehammer

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
So, mein Quellcode bis jetzt:

Java:
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)?
 
N

nillehammer

Gast
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)?
Ja, genauso ist es.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
Juhu, schön langsam verstehe ich das Konzept :D 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:

Java:
/***********************************************************************************
      * 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:
 
N

nillehammer

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
Toll, danke! Damit wäre der erste Teil jetzt fertig... Allerdings verwirrt mich Punkt 1 bei der Methode longAsIpStr etwas, also:
Code:
-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.
 
N

nillehammer

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
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)
 

Mampf

Mitglied
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:
Java:
for(int i = 0; i < intArray.length; i++) {
            intArray[i] = value&temp; //value ist der eingelesene long, temp 255.
            //shift
        }
 
N

nillehammer

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

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

Java:
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
            
        }
 
N

nillehammer

Gast
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

Mitglied
Also die IDE gibt mir bei
Java:
intArray[i] = value&temp;
einen "possible loss of precision", da von long zu int konvertiert wird. Gibt es da eine bessere Methode?
 
N

nillehammer

Gast
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)?
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
Meine Methode sieht einstweilen so aus:

Java:
 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;
    }
 
N

nillehammer

Gast
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

Mitglied
Der Laufzeitfehler:
Code:
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?
 
N

nillehammer

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
Aha...
Java:
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 :)
 
N

nillehammer

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

Mampf

Mitglied
Der Code:
Java:
 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
Java:
value = value >> 8;
zu tun hat:
Code:
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
 
N

nillehammer

Gast
Code:
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.
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
Die Methode funktioniert!

Code:
Java:
 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?
 
N

nillehammer

Gast
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!
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
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.
 
N

nillehammer

Gast
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. :eek: 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

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

Java:
/*************************************************************************************************************    
      *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:
Code:
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:

Java:
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 ;)
 
N

nillehammer

Gast
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!
 
Zuletzt bearbeitet von einem Moderator:

Mampf

Mitglied
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 :D (bin aus Österreich)
 
Zuletzt bearbeitet:
N

nillehammer

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:
N

nillehammer

Gast
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

Mitglied
Ok, der Netzwerkteil als String kommt raus, wenn ich

Java:
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.
 
N

nillehammer

Gast
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

Mitglied
OK, der Code für die niedrigste IP funktioniert schonmal:
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
        
        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 :p
 
N

nillehammer

Gast
[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

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

nillehammer

Gast
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.
 
Zuletzt bearbeitet von einem Moderator:

Neue Themen


Oben