Odbiór dużej ilości socketów

Odbiór dużej ilości socketów
KA
  • Rejestracja:prawie 21 lat
  • Ostatnio:30 dni
  • Postów:700
0

Cześć,
stworzyłem aplikacje klient-serwer. Serwer wysyła do klienta dane w postaci: "pole|pole|pole|pole". Pojawił mi się problem w momencie kiedy wysyłam duże ilości danych.

Klient odbierając pakiet, odpala nowy wątek, który obrabia sobie te dane.

Problemem jest to, że kiedy wysyłam w pętli dużo takich pakietów to klient nie wyrabia z obsługiwaniem tego. Części nie wyłapuje, część pakietów dochodzi połączona i wtedy klient świruje.

Rozwiązałem to dając przy każdym przejściu pętli po stronie serwera sleepa, żeby klient miał czas odpalić wątek. Czy jest to jednak eleganckie rozwiązanie? Czy jednak powinienem spróbować dodać jakiś znak końca pakietu i czekać po stronie klienta aż dojdzie całość ewentualnie wtedy to sobie obrabiać?

W tym przypadku sleep zdaje egzamin ale kiedy kilka watkow z serwera wysle do klienta pakiety to moga pojawic sie problemy.

Czy jestem przewrazliwiony czy jednak powinienem to inaczej rozwiazac? :) Moge prosic o porade?

pozdrawiam!


Kto nigdy nie zrobił var dupa niech pierwszy rzuci kamień.
xfin
  • Rejestracja:ponad 11 lat
  • Ostatnio:9 miesięcy
  • Lokalizacja:Genewa
  • Postów:597
1

Ale lecisz na TCP czy UDP?

W przypadku TCP masz mechanizmy kontroli, które powinny zapobiegać gubieniu się pakietów.
W UDP musisz sam zadbać o taki mechanizm.

Ja jednak mam podejrzenie (jeśli jeszcze tego nie sprawdziłeś), że problem może być z buforem, który trzyma te pakiety w kolejce do obrobienia.

KA
  • Rejestracja:prawie 21 lat
  • Ostatnio:30 dni
  • Postów:700
0

Lece na TCP. Większy problem moim zdaniem teraz to łączenie się tych pakietów. Pewnie powinienem dać jakiś znak końca pakietu żebym przy obrabianiu wiedział gdzie się kończy a gdzie zaczyna następny.

W aplikacji klienta w funkcji receive jedyne co mam to odpalenie wątku i wrzucenie odebranych informacji do niego.

Nie wiem jak to rozwiązac inaczej w sytuacji kiedy pakiet jest zlepkiem dwóch gdzie drugi jest niepełny. Wrzucic to gdzieś do bufora, zakończyć na tym wątek i czekac aż przyjdzie kolejna część pakietu i wtedy w następnym wątku sprawdzić czy w buforze coś nie czeka?

//edit
hmm a moze w tych watkach wrzucac wszystko do jednego bufora i zostawic obsluge tego jednemu wydzielonemu watkowi?


Kto nigdy nie zrobił var dupa niech pierwszy rzuci kamień.
edytowany 1x, ostatnio: karpov
kaczus
  • Rejestracja:około 10 lat
  • Ostatnio:5 dni
  • Lokalizacja:Łódź
  • Postów:1402
0

Nigdy nie masz pewności, że dostaniesz ramkę w całości, to chyba normalne, że musisz zbierać dane do bufora i je analizować....


Ogólnie na prace domowe mam stawki zaporowe. Czasem coś o programowaniu znajdzie się na mojej stronie
xfin
CZy w Delphi/Pascalu to jest jakiś problem? Przecież po to jest TCP, żeby udostępnić użytkownikowi dane i żeby sam nie musiał się bawić w składanie ramek.
kaczus
ty wysyłasz, ale jak polaczy to w ramki sterownik - tego nie możesz byc pewien - nie masz nad tym kontroli ani spod delphi, ani spod c - tak działa tcp - po prostu wysyłasz i odbierasz
KA
  • Rejestracja:prawie 21 lat
  • Ostatnio:30 dni
  • Postów:700
0

Domyślam się, dlatego pytam jak to się rozwiązauje 'standardowo' żebym nie wymyślał jakiś własnych dziwacznych rozwiązań ;)


Kto nigdy nie zrobił var dupa niech pierwszy rzuci kamień.
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:minuta
  • Lokalizacja:Gorlice
0

Nie czaję odbierając pakiety masz pętlę w której po odebraniu części danych (obieg pętli) odpalasz wątek który ma obrobić te dane i się zakończyć i po tym dopiero byś chciał odebrać następną część danych?


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
abrakadaber
abrakadaber
  • Rejestracja:ponad 12 lat
  • Ostatnio:8 miesięcy
  • Postów:6610
1

wątek obsługujący połączenie (1) (TYLKO odbiera dane i zapisuje do bufora)
|
/
bufor FIFO
|
/
wątek obrabiający dane z bufora (2)

  1. działa tylko na czas połączenia klienta i a tylko odebrać i zapisać do bufora dane
  2. działa dopóki nie skończą się dane w buforze i (1) zasygnalizuje, że skończył odbierać

Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
szopenfx
  • Rejestracja:prawie 21 lat
  • Ostatnio:5 miesięcy
1

Tak jak już zostało to powiedziane pakiety mogą się sklejać lub przychodzić pocięte (tzn. część w 1 pakiecie kolejna w następnym).

Ja realizuje to w ten sposób - jest 1 wątek, który zajmuje się odbieraniem i składaniem pakietów - tutaj w zależności czy jest to połączenie synchroniczne czy asynchroniczne będziesz miał albo nieskończoną pętlę czekającą na dane z bufora albo zdarzenie, które wywoła twój event, sprowadza się to do tego samego...
Czyli do dzielenia sklejonych pakietów lub czekania na nadejście kolejnego chunk'a. Jeśli już złożę jeden pakiet w całość wg. protokołu - u ciebie będą pewnie rozdzielone | (pipeline) to robie Event od faktycznego "odbieracza", który już ma pewność że pakiet przyszedł jeden cały (czyli zawartość pomiędzy ||) i można zająć się obróbką faktyczną pakietu.

KA
  • Rejestracja:prawie 21 lat
  • Ostatnio:30 dni
  • Postów:700
0

Zrobiłem taką procedurę. Działa poprawnie, rozdziela komunikaty od serwera nawet jeżeli przylecą sklejone w jednym sockecie. Jeżeli jakiś został rozdzielony to również go skleja. Na pewno można to zapisać o wiele prościej ale już dzisiaj późno i stać mnie było tylko na takie coś ;)

Kiedy przychodzą pakiety to wrzucam je do "Bufor", który jest typu TStringList. Zabezpieczam to wszystko TCriticalSection.
Dodalem wiecej komentarzy zeby latwo bylo sie zorientowac o co chodzi.

Kopiuj
procedure TObslugaBufora.Execute;
var
  stop,P,K:integer;
  socket, komunikat, urwany:string;
  koniec:boolean;
begin

stop:=0;              //na potrzeby nieskonczonej petli, ktora sprawdza bufor
urwany:='';          //tu bedzie trzymany fragment urwanego komunikatu

  repeat               //zaczynamy nieskonczona petle

    socket:='';       //zerujemy przed pobranie z bufora

      CSBufor.Enter;

      if Bufor.Count>0 then
      begin
      socket:=Bufor[0];     //pobieramy z bufora i wyrzucamy z niego pobrany socket
      Bufor.Delete(0);
      end;

      CSBufor.Leave;

      if socket<>'' then      //jezeli cos jest w buforze...
      begin

        repeat                    //obrabiamy socket az wydzielimy wszystkie komunikaty

          koniec:=false;       //jezeli zakonczymy prace nad socketem

           //kazdy komunikat zaczyna sie znakiem <
           //a konczy > np. <test1|test2|test3|test4>

          if urwany<>'' then  //poprzedni socket konczyl sie urwanym komunikatem
          begin

            K:=AnsiPos('>', socket);

            komunikat:=Copy(socket, 1, K);
            urwany:=urwany+komunikat;

            Delete(socket, 1, K);

            Przekaz(urwany);     //docinamy brakujacy fragment i przekazujemy do wlasciwej obrobki

            urwany:='';

          end;

          P:=AnsiPos('<', socket);    
          K:=AnsiPos('>', socket);

            if (P<>0)and(K<>0) then //jezeli znaleziono kolejny komunikat
            begin

              komunikat:=Copy(socket, P, K);
              Delete(socket, P, K);

              Przekaz(komunikat);       //docinamy i przekazujemy do obrobki

            end         //znalezlismy juz wszystkie pary w sockecie
            else
            begin
              koniec:=true;
            end;

            if (P<>0) and (K=0) then  //jezeli ostatnia para jest urwana
            begin
              urwany:=socket; //reszta, ktora zostala z socketa, zostanie doklejona przy nastepnym sockecie
              koniec:=true;
            end;

        until koniec;    //koniec obrobki socketu

      end;

  Sleep(50);          //chwile spimy
  until stop=1;       //nieskonczona petla


end;

A dziala to tak:

Dane wejsciowe:

Kopiuj
Socket1:
<test0|test2|test3|test4|test5|test6><test1|test2|test3|test4|test5|test6><test2|test2|test3|test4|test5|test6><test3|test2|test3|test4|test5|test6><test4|test2|test3|test4|test5|test6><test5|test2|test3|test4|test5|test6><test6|test2|test3|test4|test5|test6><test7|test2|test

Socket2:
3|test4|test5|test6><test8|test2|test3|test4|test5|test6><test9|test2|test3|test4|test5|test6><test10|test2|test3|test4|test5|test6><test11|test2|test3|test4|test5|test6><test1

Socket3
2|test2|test3|test4|test5|test6>

Dane wyjsciowe:

Kopiuj
<test0|test2|test3|test4|test5|test6>
<test1|test2|test3|test4|test5|test6>
<test2|test2|test3|test4|test5|test6>
<test3|test2|test3|test4|test5|test6>
<test4|test2|test3|test4|test5|test6>
<test5|test2|test3|test4|test5|test6>
<test6|test2|test3|test4|test5|test6>
<test7|test2|test3|test4|test5|test6>
<test8|test2|test3|test4|test5|test6>
<test9|test2|test3|test4|test5|test6>
<test10|test2|test3|test4|test5|test6>
<test11|test2|test3|test4|test5|test6>
<test12|test2|test3|test4|test5|test6>

Kto nigdy nie zrobił var dupa niech pierwszy rzuci kamień.
edytowany 3x, ostatnio: karpov

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.