przesyłanie plików za pomocą Client/Serwer Socket

0

Witam
Przeczytałem wiele wątków, także artykułów, a mimo to kod nie działa jak powinien.
Ogólnie rzecz biorąc, mamy dwa programy serwer i klient, wymiana wiadomości działa.
Problem zaczyna się jeżeli jeden program chce przesłać plik do drugiego.

Schemat działania wygląda następująco,

  1. Klient wysyła wiadomość do serwera (komendę) na którą serwer odpowiada wysłaniem pliku
  2. Serwer wysyła plik w partiach po 1 kB, po wysłaniu każdej z partii oczekuję na wiadomość od klienta, że ten już odebrał daną partię.

Poniżej kod serwera

procedure TForm1.SendFile(const FileName: String);
var
  Src : File;
  BytesRead : Integer;
  Buffer : array[0..1023] of char;  // bufor przesyłanych danych
  petla : Integer;
begin
  petla := 0;
  AssignFile(Src, FileName); //przypisanie pliku do Scr
  Reset(Src, 1);  // otwarcie pliku
  while BytesRead > 0 do // pętla wykonywana dopóki zmienna BytesRead będzie większa od 0
  begin
    Inc(petla);
    if (petla = 1) then
    begin
      BlockRead(Src, Buffer, SizeOf(Buffer), BytesRead); // odczytaj porcje danych 1024bity do zmiennej Buffer
      ServerSocket1.Socket.Connections[0].SendBuf(Buffer, BytesRead);
    end
    else
    begin
      while (flaga = 0) do //zmienna globalna, gdy zero serwer oczekuje, gdy 1 znaczy ze klient odebral partie
      begin
        Application.ProcessMessages;
      end;

      if (flaga = 1) then
      begin
        BlockRead(Src, Buffer, SizeOf(Buffer), BytesRead); // odczytaj porcje danych 1024bity do zmiennej Buffer
        try
          ServerSocket1.Socket.Connections[0].SendBuf(Buffer, BytesRead);
          flaga := 0; 
        except
        end;
      end;

    end;
  end;

Ponizej kod klienta

var
  Buffer : array[0..1023] of char;
  RealSize : Integer;
  F : File;
begin
    AssignFile(F, 'plik.bmp');
    Rewrite(F, 1); // stworzenie nowego...
    RealSize := Socket.ReceiveBuf(Buffer, SizeOf(Buffer));
    BlockWrite(F, Buffer, RealSize); // zapisz tę porcję do oddzielnego pliku
    ClientSocket1.Socket.SendText('ok');//wiadomosc do serwera ze odebrany plik
end;

Prosiłbym o wyjaśnienie, gdzie jest błąd w moim rozumowaniu.

0
  1. po co ta odpowiedź? Jak się nie uda to dostaniesz exception - tcp to zapewnia.
  2. oczywiście nie napisałeś jakie są objawy bo po co...
0

Ad.1
Zrobiłem test, sprawdzający ilość wysłanych partii na serwerze, oraz ilość odebranych na kliencie.
Gdy nie było, schematu z odpowiedzią, na 12220 wysłanych ze strony serwera, klient złapał 200.
Widziałem w tematach, że ludzie mają zwyczaj rozwiązywać ten problem poprzez sleep na serwerze by klient zdążył zapisać dane,
ja nie lubię używać sleep, więc zdecydowałem się wprowadzić takie rozwiązanie.

Ad.2
Faktycznie, umknęła mi ta informacja :)
Wydaję mi się, że klient zapisuję do pliku bmp partie po 1kB, ale gdy otrzymuje kolejne partie, nie dopisuje do pliku a podmienia ten plik,
gdyż plik po stronie klienta zajmuję z reguły 963 kB czyli tak jakby tylko ostatnia przesłana partia.

2

gdyż plik po stronie klienta zajmuję z reguły 963 kB czyli tak jakby tylko ostatnia przesłana partia.

A czy ty przypadkiem nie nadpisujesz pliku przy każdym pakiecie?

Jeszcze jedna ważna sprawa przy przesyłaniu plików przez sockety: Nie wiem jaki sposób rozdzielania wiadomości stosujesz (często jest to #13#10) ale jeżeli w pliku będzie taka kombinacja to jej wysłanie skończy się urwaniem wiadomości. Więc trzeba zrobić jakiś system który zamieni te dane na inne a potem znowu przywróci postać pierwotną. Dodatkowo radzę żeby za wszystko odpowiadały komendy (np. file_chunk <zawartość>, send_next, send_done itd) z parametrami o ile nie jest to jakiś naprawdę podstawowy przykład.

I nie jestem pewien co to za pakiet internetowy, czyżby INDY?

Btw. nie rozumiem tego
if (petla = 1) then - tak się nie robi wysyłania plików, rób to poza pętlą, gdzieśtam, ale czemu tak?

Ah, i jak już zauważyłem że mamy doczynienia z kimś nieobeznanym, to ja bym na sam wpierw radził użyć zapomnianego przez nowych narzędzia jakim jest DEBUGGER, pozwoli ci on zobaczyć co się nie wykonuje poprawnie itd. A jak go używać? wygogluj np. 'delphi debugger używanie'.

1 użytkowników online, w tym zalogowanych: 0, gości: 1