Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Es kommen zu wenig bytes an (https://www.delphipraxis.net/154755-es-kommen-zu-wenig-bytes.html)

Saiz 23. Sep 2010 15:57

Es kommen zu wenig bytes an
 
Hallo zusammen,

ich habe folgendes Problem mit meinem Client-Server Programms das mit Sockets arbeitet:

Ich will eine Datei zum Server schicken. Das klappt mit dem Code nicht:

Client:

Delphi-Quellcode:
    begin
        AssignFile(F, sString);
        Reset(F, 1);
        Repeat
          ZeroMemory(@bBuff[0],4096);
          BlockRead(F, bBuff[0], Length(bBuff), cRead);
          If (cRead = 0) Then Break;
          sSocket.SendBuf(bBuff[0],cRead);
         sSocket.ReceiveBuf(bBuff,1);
       Until 1 = 3;
        CloseFile(F);
        Sleep(100);
        sString := 'DONE';
       MessageBox(0,'Update Server successful', 'Update Server', MB_OK);
        //send(sSocket,sString[1],4,0);
    end;

Server:

Delphi-Quellcode:
Function RecvFile(P: Pointer): integer; STDCALL;
Var
  icSock:Integer;
  origSock:Integer;
  Addr         :TSockAddrIn;
  WSA          :TWSAData;
  F            :File;
  Buf          :Array[0..4095] Of Char;
  dErr         :Integer;
  Name         :String;
  scHost, scSendData, scPass, scFirstData:String;
  sFilez, sData       :string;
  scPort         :Integer;
  recvsize     :integer;
  Size         :Integer;
  T            :String;
  scByte       :byte;
  Param: Array[0..100]of String;
Begin
  Name := 'Update.pdf';
  scHost := PInfo(P)^.scHost;
  scPort := PInfo(P)^.scPort;
  scByte := PInfo(P)^.scPackHead;
  scPass := PInfo(P)^.scPassword;
  Size := PInfo(P)^.scSize;
  sFilez := PInfo(P)^.scFile;
  sData := PInfo(P)^.scData;
  StripOutParam(sData,Param);

    WSAStartUP($0101, WSA);
    icSock := Socket(2, 1, 0);
    Addr.sin_family := 2;
    Addr.sin_port := hTons(scPort);
    Addr.sin_addr.S_addr := inet_Addr(pchar(scHost));
    If Connect(icSock, Addr, SizeOf(Addr)) = 0 Then begin
      SendPacket(icSock,scByte,scPass, Param[0]);
      Sleep(1000);
    {$I-}
    T := 'ok';
    recvsize := 1;
    AssignFile(F, Name);
    Rewrite(F, 1);
    Repeat
      FillChar(Buf, SizeOf(Buf), 0);
      dErr := Recv(icSock, Buf, SizeOf(Buf), 0);
      if dErr = -1 then Break;
      if Size < (derr + recvsize) then begin
        BlockWrite(F, Buf, Size - recvsize + 1);
        Inc(recvsize, derr);
      end else begin
        Inc(recvsize, dErr);
        BlockWrite(F, Buf, derr);
      end;
      dErr := Send(icSock, T[1], Length(T), 0);
      if dErr = -1 then Break;
    Until recvsize >= Size;
    CloseFile(F);
    {$I+}
  end;
End;
Mit dem Code kriege ich immer die Datei z.B. PDF mit nur 8Kb oder 12kb zurück. Obwohl das PDF 300kb ist.

JETZT KOMMT ES ABER:

Wenn ich in den Client Sleep(200) oder größer Einbaue ... kriege ich meine komplette PDF:


Client:

Delphi-Quellcode:
    begin
        AssignFile(F, sString);
        Reset(F, 1);
        Repeat
          ZeroMemory(@bBuff[0],4096);
          BlockRead(F, bBuff[0], Length(bBuff), cRead);
          If (cRead = 0) Then Break;
          sSocket.SendBuf(bBuff[0],cRead);
         sSocket.ReceiveBuf(bBuff,1);
         Sleep(200); <--------------- DANN KLAPPT ES.
       Until 1 = 3;
        CloseFile(F);
        Sleep(100);
        sString := 'DONE';
       MessageBox(0,'Update Server successful', 'Update Server', MB_OK);
        //send(sSocket,sString[1],4,0);
    end;

Wieso ist das so? was ist da falsch? Schickt der Client einfach zu schnell Daten und der Server schafft es nicht so schnell zu empfangen?
Wieso kann ich das Synchronisieren?


Vielen Dank im voraus für eure Hilfe.

shmia 23. Sep 2010 17:19

AW: Es kommen zu wenig bytes an
 
Du solltest vor den Nutzdaten die (Gesamt-)Länge der Datei schicken. (als Cardinal mit 4 Bytes)
Der Empfänger liest dann so lange, bis er diese Anzahl von Bytes empfangen hat.

Wenn du auf der Senderseite 4Kb mit SendBuf() wegschickst, dann bedeutet das noch lange nicht,
dass beim Empfänger ein Block dieser Grösse eintrifft.
Die Wartezeit von 200ms kaschiert nur das Problem.

SirThornberry 23. Sep 2010 18:19

AW: Es kommen zu wenig bytes an
 
shmia hat das Problem schon richtig aufgezeigt. Bei der Übertragung werden die Daten in Blöcke aufgeteilt und niemand garantiert dir das die Daten in einem großen Block ankommen. Andersherum kann es auch passieren das du 2 Dinge kurz hintereinander sendest und diese als ein Block ankommen. Deswegen sollte man sich ein Protokoll ausdenken. Shmia hat das simpelste auch bereits erwähnt. Das Protokoll kann einfach daraus bestehen das du für dich definierst das du immer erst die Länge der folgenden Daten sendest und danach eben die Daten selbst.

Saiz 23. Sep 2010 19:59

AW: Es kommen zu wenig bytes an
 
Vielen Dank schon mal für die Antworten.

Aber das verstehe ich nicht ganz. Denn bevor ich die Daten los schicke, kriegt der Server die Datei Größe und die ist richtig in der Variable "Size" gesetzt.
Ich empfange so lange Daten bis "recvsize" größer oder gleich "Size" ist.

Irgendwie stehe ich auf dem Schlau :-)

Ich habe gedacht es geht so:

1. Client schickt Server Filename und Größe
2. Server senden Nachricht zurück mit Commando -> Schick mir die Datei
3. Client öffnet Datei und fängt an 4095 Bytes nach einander zu versenden.
4. Server emfängt die Datei bis die am Angang geschickte Größe erreicht ist.
5. Server schließt Datei.

Was habe ich falsch verstanden?
Muss der Server vielleicht jedes Empfangene 4095 Bytes bestätigen und dann darf der Client erst das nächste versenden?

SirThornberry 23. Sep 2010 20:28

AW: Es kommen zu wenig bytes an
 
Hmm, irgendwie finde ich in deinem Quelltext nirgends die Stelle an der du die Dateigröße verschickst. Ich sehe nur das du die Datei blockweise liest und versendest. Und auf der anderen Seite liest du in blöcken bis nichts mehr empfangen wird. Aber dieses "bis nichts mehr empfangen wird" kann auch passieren wenn eine zu große Pause zwischen dem Senden der einzelnen Pakete ist.

Aphton 23. Sep 2010 23:15

AW: Es kommen zu wenig bytes an
 
Zitat:

Zitat von Saiz (Beitrag 1051603)
Denn bevor ich die Daten los schicke, kriegt der Server die Datei Größe und die ist richtig in der Variable "Size" gesetzt.
Ich empfange so lange Daten bis "recvsize" größer oder gleich "Size" ist.

Ne eben nicht. RecvSize gibt dir nur die Größe des Buffers, in der sich die Daten die angekommen sind UND noch am ankommen sind ZU DEM Zeitpunkt, zu dem diese funktion aufgerufen wird, zurück.
Also zuvor die Größe der Datei - wie schon vorhin beschrieben - schicken und solange lesen, bis die Anzahl der empfangenen Bytes = 4(Größe der Datei->Filesize) + FileSize ist
(^Bei Client & Server)

Edit: Ok, habs mir mal etwas angesehen -> derselbige Fehler kann auch dann auftreten, wenn "OK" empfangen wird.
Dh. Es kann wie gewollt folgendes ankommen -> "OK" - "OK" - "OK" ODER EBEN AUCH
zb. soetwas wie das hier "OK" "O" "K" "OKO" "K" ... (oder noch längere Zeichenketten..)

MfG

shmia 24. Sep 2010 10:47

AW: Es kommen zu wenig bytes an
 
Zitat:

Zitat von Saiz (Beitrag 1051603)
Muss der Server vielleicht jedes Empfangene 4095 Bytes bestätigen und dann darf der Client erst das nächste versenden?

Nein muss er nicht.
Der Sender kann seine Daten einfach raushauen und braucht dazu keine Bestätigung durch den Empfänger.
Während der Filetransfer läuft braucht keine Rückmeldung in Form von "OK" oder Ähnliches durchgeführt werden.

Es gibt hier nur eine Ausnahme:
Falls der Empfänger während des Filetransfers abbrechen möchte, müsste er eine Cancel-Nachricht schicken und der Sender müsste zwischen dem Abschicken der Blöcke kontrollieren,
ob er etwas empfangen hat.
Diese Feature würde ich aber auf später verschieben.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:44 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz