{
  Joachim Deckers
  Anlage zur 2. Staatsexamensarbeit / 28.5.96

  Lösungsvorschlag zu den Aufgaben 8 und 9 im Abschnitt
  "7.3.5.4 Fragmentierung und paketweise Übermittlung"

  Die Verwendung einer Unit wird in den Aufgaben zwar nicht gefordert,
  erscheint aber zweckmäßig, wenn den Schülerinnen und Schülern der
  Umgang mit Units vertraut ist.
}


unit protp3;

INTERFACE

type      kennung = byte;

const     Feldgroesse = 100; { Größe eines Datenpaketes
                               (inkl. Protokollkopf) }

procedure SendePkte(von, an: kennung; laenge: Word; feld: PChar);
function  EmpfangePkte(    ich: kennung;      
                       var von: kennung;
                       var laenge: word;
                           feldgroesse: word;    { Größe des Feldes für die Nachricht }     
                           feld: PChar): boolean;{ Feld für die Nachricht }


IMPLEMENTATION

uses  protokoll, protp2, strings,
      WinCRT;

const ProtKenn     = 'P'#3;
      ProtOverhead = 2 + 4;        { Zusätzliche Bytes für Pakettransfer }
      MaximalePaketLaenge = Feldgroesse - ProtOverhead;
                                   { Overhead des Protokolls P2 wird
                                     nicht berücksichtigt (die Paketlänge
                                     ist hier also die Länge der Nachricht
                                     für P2) }

                                                                          
procedure SendePkte(von, an: kennung; laenge: Word; feld: PChar);
var lfdNr, insgesamt, pos: Word;
    s       : string;
begin
  insgesamt := (laenge div MaximalePaketLaenge) + 1;
  { Zuerst haben alle Pakete die gleiche Länge } 
  for lfdNr:=1 to insgesamt-1 do begin
     pos:=(lfdNr-1)*MaximalePaketLaenge;
     PCharInString(MaximalePaketLaenge,@feld[pos],s);
     s:=ProtKenn+word2string2(lfdNr)+word2string2(insgesamt-lfdNr)+s;
     { Laufende Nummer und Anzahl noch ausstehender Pakete davorschreiben }
     SendeP(von,an,s);

     { Und jetzt noch 10 Zentisekunden = 0,1 Sekunde warten,
       damit ggf. auch andere Prozesse ihre Nachrichten schicken
       können. Gehört nicht zur Aufgabenstellung, ist sinnvoll,
       wenn die Protokolldatei nicht auf einem Netzwerkserver liegt. }
     Warte(10);
  end;
  { Das letzte Paket könnte kürzer sein }
  pos:=(insgesamt-1)*MaximalePaketLaenge;
  PCharInString(laenge - pos,@feld[pos],s);
  s:=ProtKenn+word2string2(insgesamt)+word2string2(0)+s; { Laufende Nummer und Anzahl noch ausstehender Pakete davorschreiben }
  SendeP(von,an,s);
end;

function  EmpfangePkte(ich: kennung; var von: kennung; var laenge: word; feldgroesse: word; feld: PChar): boolean;
var nochzuempfangen,
    lfdNr, letzteNr,
    nachrlaenge,
    anzahl             : word;
    s                  : string;
    absender           : kennung;
    fehler             : boolean;

  function min(a,b:integer):integer;
  begin
    if a<b then min:=a else min:=b
  end;
       
begin
  letzteNr:=0;
  laenge  :=0;
  fehler:=NOT EmpfangeP(ich, absender, s);
  if (s<>'') then begin
    von:=absender;
    if not fehler then
    repeat
      if Copy(s,1,2) = ProtKenn then begin 
        lfdNr:=char2word(s[3],s[4]); { laufende Nummer auslesen }
        if lfdNr<>letzteNr+1 then begin
          fehler:=true;
          writeln('Fehler: Paket ',lfdNr,' nach Paket ',letzteNr,' erhalten.');
        end
        else begin
          letzteNr       :=lfdNr;                 { für das nächste Paket merken       }
          nochzuempfangen:=char2word(s[5],s[6]);  { wieviele Pakete noch? (0 = fertig) }
          anzahl         :=Length(s)-ProtOverhead;
          if (laenge+anzahl)<feldgroesse then     { Paßt es noch ins Feld? } 
            StrPCopy(@feld[laenge],Copy(s,7,anzahl));
          inc(laenge,anzahl);                     { anzahl hochzählen }
          if nochzuempfangen>0 then               { ggf. nächstes Paket holen }
            fehler := NOT EmpfangeP(ich,absender,s);
        end;
      end
      else
        fehler:=true; { Keine Protokollkennung gefunden } 
    until fehler or (von<>absender) or (laenge=feldgroesse-1) or (nochzuempfangen=0) or (s='');

    if (nochzuempfangen=0) and   { alle Pakete erhalten,       }
       (von=absender) and        { immer vom gleichen Absender,}
       (laenge<feldgroesse) and  { Nachricht paßte in das Feld }
       not fehler then           { und sonst kein Fehler       }
      EmpfangePkte:=true         { => Nachricht kann verwendet werden   }
    else
      EmpfangePkte:=false        { => Fehler, Nachricht nicht verwenden }
  end { if s<>'' then ... }

  else begin { leere Nachricht erhalten, kein Fehler }
    EmpfangePkte := true;
    laenge:=0;
  end;
end;

begin
end.
