Odczyt danych z socketa (zlecenie)

0

Witam.
Nie wiem juz jak to mam zrobic. Wszytskie dane mam potrzebne, wiem tez w <ort>teori </ort>jak to zrobic
ale nie wiem czemu zupelnie dostaje inne smieci podczas odczytu danej czesci pakietu.
Jesli ktos ma ochote to chetnie zlece zrobienie takiego malego modulu na odbior danych ,ktore
beda czekaly w buforze. Nastepnie pobierane z niego i prrzetwarzane.

Wszystkie funkcje przetwarzania mam a takze zasade zbierania danych z socketa.
Kropk po kroku:

  1. Pobieramy 4 bajty z ktorych odczytujemy jaka jest wielkosc pakietu
  2. Zmniejszamy wielkosc pakietu o te 4 bajty i znamy wielkosc reszty pakietu
  3. pobieramy reszte pakietu i sprawdzamy czy pobrane dane to nasza oczekiwana wielkosc
  4. jesli nie to zmniejszamy oczekiwana wielkosc o wielkosc wlasnie pobranego pakietu
    i wysylamy zadanie by pobrac kolejne co pozostalo
  5. wracamy do punktu 3
  6. jesli wielkosc jest oczekiwana wstawiamy dane do bufora kolejkowaego
  7. jesli sa juz dane w buforze to odczytujemy i je prztwarzamy wedlug wlasnego uznania
  8. kasujemy z bufora to co odebralismy i przetworzylismy tak by bufor byl na bieŻąco kasowany
    aby nie nastapilo jego przepelnienie.

Jak cos prosze o maila
[email protected]

0

kod, koD, kOD, KOD daj waćpan. Co i jak wysyłasz i jak odbierasz

0

Zatem tak:
Na formie wrzucilem TClientSocket ten z delphi 7 co sie doinstalowuje z paczki wiec sadze ze to takie standardowe. Pierwsza z funkcji jest jedna ze znalezionych na 4p, i wyglada ona tak:

const
SOI = SizeOf(Integer);
SOW = SizeOf(Word);
SOB = SizeOf(Byte);


procedure Rvrs(var Buf; Count: Integer);
var
  S: String;
  I: Integer;
begin
  SetLength(S ,count);
  Move(Buf, Pointer(S)^, Count);
  for I := 0 to Count - 1 do
    Begin
      (PChar(@Buf) + I)^ := S[Count - I];
    End;
end;

Jesli zastosuje taki kod:

   I := MainForm.ClientSocket.Socket.ReceiveBuf(SoPck, SOI);
  Rvrs(SoPck, SOI);
  Memo2.Lines.Add(IntToStr(SoPck));
  Result := (I = SOI) and (SoPck >= SOI + (2 * SOW));
  if not Result then Exit;
  Memo3.Lines.Add('Dlugosc Pakietu start: ' + inttostr(SoPck) );

Chodzi o to ze pobieram pierwsze 4 bajty [Socket.ReceiveBuf(SoPck, SOI);]
Po funkcji [Rvrs(SoPck, SOI);] w zmiennej SoPck mam wynik 410
Nastepnie program dalej rozpakowuje pakiet, pobiera sobie kolejne 2 bajty
odczytuje z nich dane i pobiera kolejne 2 bajty itd. Ale w tym zalozeniu
jest blad poniewaz zalozylem ze pakiet jaki przychodzi to przychodzi jednym odczytem
a moze sie zdarzyć, dostane kawalek pakietu. Dlatego chcialem uzyc funkcji skladajacej
pakiet do jakiegos dynamicznego przejsciowego bufora:
Poniewaz nie mam w socketach funkcji PEEK DATA czyli nie moge sprawdzic ile juz przyszlo
danych chcialem uzyc innego socketa ale nie znalalem nic. Dlatego algorytm jest taki:

  1. pobierz 4 bajty z pakietu ktory przyjdzie:
  2. Odczytaj jaka jest dlugosc pakietu (np dl = 410)
  3. W tej dlugosci jest zawarta dlugosc tych 4 bajtow wiec odejmujemy 4 bajty to dl = 410 - 4 = 406
  4. Teraz chcialem zeby program odczytal [Socket.ReceiveBuf(SoPck, 406);]
  5. Sprawdz ile przyszlo:
    a) jesli przyszlo mniej niz oczekiwane 406 to wstaw to co odczytales do bufora tymczasowego.
    Odczytaj ile juz przyszlo i odejmij od 406 to co przyszlo np:206 (406 - 206 = 200)
    wroc do punktu 4 ale odczytaj 200 bajtow
    b) Jesli przyszlo tyle co oczekiwalismy wstaw do bufora przejsciowego i wroc do punktu 1

ten bufor przejsciowy to maja byc tam juz odberane pakiety czekajace na pobranie i
rozpakowanie ich wedlug kodu ktory tez juz jest zrobiony i dziala w przypadku jesli zalozenie
to bledne jest prawdziwe. Jesli pakiet jest mniejszy wtedy odczytuje jakies syfy i program wywala
access violation czyli wiadomo ze probowal dostac sie tam gdzie nie trzeba :)

I teraz kod rozpakowujacy pakiet jest w ON READ Socket a tak moze by co sekunda dac ten kod w timerze zeby sprawdzal czy sa jakies pakiety i jesli sa niech bierze pierwszy z kolejki i zmniejsza bufor o jego wielkosc. a funkcja dodajaca pakiet niech zwieksza go o dana wielkosc pakietu. W ten sposob dynamicznie bedziemy ustawiac bufor tymczasowy ktory nigdy sie nie przepelni....

Ale nie wiem czy to dobre rozwiazanie, robie juz z miesiac ponad to i nadal nie dziala jak powinno. :(

0

wszystko pięknie ładnie tylko zabrakło tego co najważniejsze - kod, kiedy jest wołane

 I := MainForm.ClientSocket.Socket.ReceiveBuf(SoPck, SOI);

Czy robisz to w zdarzeniu czy w pętli, czy inaczej jeszcze

0

No fakt:

procedure TMainForm.ClientSocketRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
I := MainForm.ClientSocket.Socket.ReceiveBuf(SoPck, SOI);
  Rvrs(SoPck, SOI);
  Memo2.Lines.Add(IntToStr(SoPck));
  Result := (I = SOI) and (SoPck >= SOI + (2 * SOW));
  if not Result then Exit;
  Memo3.Lines.Add('Dlugosc Pakietu start: ' + inttostr(SoPck) );

Jest to w zdarzeniu ON READ na kazdy odczyt jako. nie jest to w petli :(

0
  1. Masz przecież przekazanego Socketa w zdarzeniu - po co sięgasz przez MainForm.ClientSocket?
Delphi Help napisał(a)

ReceiveBuf returns the number of bytes actually read. If no bytes are read, ReceiveBuf returns –1.

Jeśli sam piszesz i klienta i serwera to pomyśl nad opakowaniem tego w ramki.

0

Serwer jest nie moj tylko juz ma z gory ustalone ramki chyba
C do sieganie do MainForm to zapomnialem usunac bo wstawilem na chwile inny komponent
i na zdarzeniu tego probowalem siegac po ten drugi ale to do wyciecia.
A z tego HELP co napisales oznacza ze jesli podstawiam zmienna tak jak
I := Recive.... to w TYM i zwroci mi ile juz odczytalo ?

0
masterO napisał(a)

A z tego HELP co napisales oznacza ze jesli podstawiam zmienna tak jak
I := Recive.... to w TYM i zwroci mi ile juz odczytalo ?
dokładnie

0

A to odczytywac w zdarzeniu onRead ? to dobrze ze tam odczytuje te dane?
czyli np zrobic tak:

  1. I := Recive.... 4 bajty

  2. Odczytaj wielosc calego pakietu

  3. repeat A>= (odczytana wielkosc pakiet - 4 bajty)

  4. A = Recive pakiet

i czy te punkty powyzsze to dobrze ze wstawie w OnRead?

Edit:

Wstawilem na probe taki kod:

SoPck := 0;
  RecivedPck := 0;
  ReadedBuff := 0;
  AllPck := 0;
  A := 0;
  I := ClientSocket.Socket.ReceiveBuf(SoPck, SOI);
  Rvrs(SoPck, SOI);
  //ilosc pakietu mamy w SoPck
  SoPck := SoPck - SOI;
  SOPXK2 := SoPck;

  Repeat
   sleep(1000);
    SoPck := SoPck - A;
    sleep(1000);
    Memo4.lines.add('pakiet A: ' + Inttostr(soPck));
    sleep(1000);
    //wolam o caly pakiet
   A := 0;
   sleep(1000);
   A := ClientSocket.Socket.ReceiveBuf(RecivedPck, SoPck);
   sleep(1000);
   Memo4.lines.add(' odczytano z A: ' + intToStr(a));
    //w A mam liczbe jaka przyszla pakietu
   ReadedBuff := ReadedBuff + A;
   AllPck := AllPck + RecivedPck;

 Until (ReadedBuff = SOPXK2);


i tak:
Pakiet A: 406
Odczytano z A: 406
Pakiet A: 1869376973
i wyskakuje blad:
I skad sie bierze ten pakiet co ma wielkosc niby 1869376973 ???
:/

0

a możesz gdzieś dać demo tego serwera (sam exe), od którego próbujesz pobrać dane + jakaś specyfikacja co on wysyła + ten kawałek do odbierania, z którym się męczysz

0

A moze wysle to jakos na maila czy cos? masz jakis email ?

0

wysłałem Ci wiadomość na forum z mailem

0

Ok dzieki juz odpisuje , postaram sie to zweizle krotko napisac

0

A nie prościej przerzucic odebrany bufor np do strumienia i czytać pakiet jak plik? ;)

Dajmy na to prosty przykład (fragment z jednego z moich źródeł):
Pakiet typu:
[PACKET_LEN], [PACKET_TYPE],[DATA]....

              //Write buff to stream... - przerzucam bufor(tablica z odebraną ramką do strumienia)
              Stream.WriteBuffer(pBuff, pLen);

                    //Stream to akurat obiekt mojej klasy TPacketStream - potomek TMemoryStream przystosowany do pakietów (obsługa Null-Terminated Strings itd)

                    Stream.ResetStream; //stawiamy kursor na początek strumienia
                    Stream.ReadBuffer(PacketLen, SizeOf(PacketLen)); //czytam typ pakietu


                    Stream.ReadBuffer(PacketType, SizeOf(PacketType)); //czytam typ pakietu

                    //a potem ;)

                              case PacketType of
                              $F9:
                                    begin
                                    HandleHelloMsg;
                                    end;

                              $A1:
                                    begin
                                    HandleAccInfo;
                                    end;

                              $E0:
                                    begin
                                    HandleSupportTokenRequest;
                                    end;

                              else
                                    begin
                                      Console.cDisplayError('Error','Invalid packet from ['+cAddr+']');
                                      Socket.Close;
                                    end;
                          end;

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