ClientSocket odbieranie danych bez OnRead

problemy z tworzeniem programów do obsługi sieci, internetu, e-mail itp..

ClientSocket odbieranie danych bez OnRead

Nowy postprzez ch2_lbn » środa, 31 marca 2010, 09:04

kiedys zrobilem projekt klienta czata i chcialem go troche zmienic
nie do konca znam dobre rozwiazanie teraz uzywam calego kodu (odpowiadajacy za rozne odpowiedzi serwera) a jest on spory w ClientSocket1Read(TObject *Sender, TCustomWinSocket *Socket) i duzo warunkow ktore dzialaja w zaleznosci jakie żądanie wyslalem. chce aby po wyslaniu danych mozna bylo je odczytac gdy dotra w danej funkcji ktora wyslala żądanie.
Kod: Zaznacz cały
ClientSocket1->Socket->SendText(req); //wysylam jakies dane
AnsiString odebrane = ClientSocket1->Socket->ReceiveText(); // cos w tym stylu tylko zapewne to nie pobierze danych bo ich jeszcze nie odebral


nie wiem czy sie tak da ale wnioskuje ze tak cos z warunkiem lub petla

dzieki za odpowiedz.
Avatar użytkownika
ch2_lbn
 
    Windows 7Firefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez Cyfrowy Baron » środa, 31 marca 2010, 09:33

Dane odbierasz w zdarzeniu OnClientRead komponentu typu TServerSocket lub OnRead dla TClientSocket:

TServerSocket:
Kod: Zaznacz cały

void __fastcall TForm1
::ServerSocket1ClientRead(TObject *Sender,
        TCustomWinSocket *Socket)
{
 String odebrane = Socket->ReceiveText();
}
 


TClientSocket:
Kod: Zaznacz cały

void __fastcall TForm1
::ClientSocket1Read(TObject *Sender,
        TCustomWinSocket *Socket)
{
 String odebrane = Socket->ReceiveText();
}
 


Zauważ, że nie odwołujesz się do obiektu ServerSocket1 czy ClientSocket1, tylko do argumentu Socket zdarzenia OnClientRead lub OnRead. Argument ten jest typu TCustomWinSocket.

Można to robić tak jak to pokazałeś, ale w ten sposób będziesz mógł odebrać tylko ostatnią wiadomość wysłaną na Socket i do dopiero po "ręcznym" wywołaniu funkcji ReceiveText(), a to wymagałoby zastosowania zegara TTimer, a najlepiej wątku. Zdarzenia OnClientRead i OnRead nasłuchują komunikatów i odbierają je natychmiast po nadejściu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez ch2_lbn » środa, 31 marca 2010, 17:13

Cyfrowy Baron napisał(a):Dane odbierasz w zdarzeniu OnClientRead komponentu typu TServerSocket lub OnRead dla TClientSocket:
[...]
Edit: Po jaką cholerę cytujesz cały post. Następnym razem dostaniesz bana.


To jeszcze raz :) to jest sam client ktory laczy sie na czat uzywajac HTTP wysylajac metada POST i w zdarzeniu onRead ClientSocket odbieram dane czatu ale mam problem poniewaz chcialem dodac zalogowanie uzytkownika i pobranie cookie z wyslaniem tego nie mam problemu tylko nie moge dopisac kodu odebrania do kodu w onread poniewaz tam juz wykonuje calkiem inne dzialania na przyjetych danych dlatego wolal bym caly kod ktory mam w zdarzeniu OnRead rozpisac na oddzielne funkcje ktore po wyslaniu danych odbiora je czyli chcialbym zobaczyc jak wyglada kod odebrania danych na jedno wyslane zapytanie ale nie za pomoca opcji OnRead. chcialem dopisac to w nowym ClientSocket2 ale wtedy mialem jakies problemy i wyskakiwal blad socketow.
Avatar użytkownika
ch2_lbn
 
    Windows 7Firefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez Cyfrowy Baron » środa, 31 marca 2010, 17:48

Zdarzenie OnRead służy do nasłuchiwania. Teraz zastanów się! Odbieranie komunikatów powinno odbywać się w zdarzeniu OnRead, gdyż po to ono jest, ale Ty stawiasz wszystko na głowie i umieszczasz w tym zdarzeniu kod, który można by pewnie umieścić gdzieś indziej, a odbieranie komunikatów chcesz przenieść tam gdzie nie jego miejsce. Zastanów się nad tym. Problemem nie jest odbieranie komunikatów, tylko te inne zadania, które umieściłeś w zdarzeniu OnRead.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez ch2_lbn » środa, 31 marca 2010, 18:18

Cyfrowy Baron napisał(a):Zdarzenie OnRead służy do nasłuchiwania. Teraz zastanów się! Odbieranie komunikatów powinno odbywać się w zdarzeniu OnRead, gdyż po to ono jest, ale Ty stawiasz wszystko na głowie i umieszczasz w tym zdarzeniu kod, który można by pewnie umieścić gdzieś indziej, a odbieranie komunikatów chcesz przenieść tam gdzie nie jego miejsce. Zastanów się nad tym. Problemem nie jest odbieranie komunikatów, tylko te inne zadania, które umieściłeś w zdarzeniu OnRead.

no to jeszcze inaczej chce pobrac czesc pliku:
Wysylam dane do strony aby pobrac wielkosc pliku (Content-Length:)
Odbieram dane o wielkosci pliku (w onread jako Content-Length:)
i nastepnie wysylam pobranie danego ciagu z pliku (Socket->SendText(dan1))
no i kolejny krok wykona mi to co powyzej poniewaz poniewaz jest to w onRead wiec sie zapetli bedzie wysylal i odbieral a w onRead program nie wie kiedy chce wykonac akurat ta czynnosc czy inna.
Zamotane to:/
Kod: Zaznacz cały
void _fastcall TForm1::ClientSocket2Read(TObject *Sender,
     TCustomWinSocket *Socket)
{
AnsiString dane = Socket->ReceiveText();
AnsiString dane1;
dane =  dane.SubString(dane.Pos("Content-Length:"),dane.Length());
dane =  dane.SubString(1,dane.Pos("\r\n")-1);
dane =  dane.SubString(17,dane.Length());
dane1=dane;
dane=dane-100;
dane=dane+"-"+dane1;

AnsiString dan1;
dan1 =
"GET /chat/room_0.log HTTP/1.1\r\n"
"Host: nazwahosta \r\n"  //host malo wazny
"Accept: */* \r\n"
"Connection: keep-alive\r\n"
"Keep-Alive: 0\r\n"
"Accept-Range: bytes \r\n"
"Range: bytes="+dane+"\r\n\r\n" ;
ClientSocket2->Socket->SendText(dan1);

AnsiString address = Socket->ReceiveText();
address = address.SubString(address.Pos(nick1),address.Length());
address = address.SubString(address.Pos("IP- ")+4,address.Length());
address = address.SubString(1,address.Pos("\n")-1);
}


Uzywalem ifow dla zmiennej zeby wykonac to co chce ale bylo duzo problemow bo jeszcze w tym kodzie jest cala obsluga czata czyli odbieranie wiadomosci. Dlatego chcialem odbierac dane w funkcji w ktorej je wysylam badz jakis bardziej alternatywne rozwiazanie
Avatar użytkownika
ch2_lbn
 
    Windows 7Firefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez Cyfrowy Baron » czwartek, 1 kwietnia 2010, 08:39

Odbieranie komunikatów musi odbywać się w OnRead. Jeżeli odbierasz różne komunikaty, to musisz umieścić w funkcji OnRead warunki, które będą filtrowały te komunikaty i jeżeli jest to komunikat zawierający informacje o pliku, to prześle je do jednych zmiennych globalnych lub funkcji, które dalej coś z tym zrobią, jeżeli będzie to zwykłą wiadomość to prześle to tam gdzie jego miejsca.

Po co umieszczasz tyle kodu w zdarzeniu OnRead, przecież możesz stworzyć funkcje, która będzie to przetwarzała. czyli funkcję sprawdzają jaki tym danych został odebrany i kolejne dwie funkcje przesyłające dalej komunikat w zależności czy jest to info o pliku, czy wiadomość, czyli coś w tym rodzaju:


schemat:
Kod: Zaznacz cały

void __fastcall TForm1
::PrzetworzPlik(String dane)
{
  // przetwarza plik
}
//-----------------------------------------------------------------------------
void __fastcall TForm1::Wyswietl_wiadomos(String dane)
{
  // przetwarza wiadomosc
}
//-----------------------------------------------------------------------------
void __fastcall TForm1::SprawdzJakiTypDanych(String dane)
{
  if(dane == zawiera_info_o_pliku) PrzetworzPlik(dane);
  if(dane == zwykla_wiadomosc) Wyswietl_wiadomosc(dane)
}
//-----------------------------------------------------------------------------
void _fastcall TForm1::ClientSocket2Read(TObject *Sender,
     TCustomWinSocket *Socket)
{
   String dane = Socket->ReceiveText();

   SprawdzJakiTypDanych(dane);
}
 


Teraz kod jest uporządkowany. Funkcja SprawdzJakiTypDanych analizuje treść komunikatu i w zależności do tego co zawiera przesyła to do odpowiedniej funkcji celem dalszego przetworzenia. Wszystkim steruje funkcja SprawdzJakiTypDanych a ni zdarzenie OnRead.



Dlaczego w zdarzeniu OnRead dwa razy odbierasz ten sam komunikat, raz tak: AnsiString dane = Socket->ReceiveText();
i drugi raz tak: AnsiString address = Socket->ReceiveText(); Wystarczy raz, zmienna dane zawiera już potrzebne dane więc nie należy wywoływać ponownie funkcji ReceiveText() tylko przepisać zawartość zmiennej dane do zmiennej address. Najlepiej by było gdy zmienna dane była typu const by nie można jej było przez przypadek zmodyfikować. Jeżeli zastosujesz się do mojego schematu, to wogóle nie ma to znaczenia.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez ch2_lbn » czwartek, 1 kwietnia 2010, 18:53

Kod: Zaznacz cały
void __fastcall TForm1::obslugaczata(String strona)                               //obsluga czata z OnRead
{
AnsiString danan;                                                               //zmienna przechowywujaca tylko dane czatowe
   strona = strona.SubString(strona.Pos("<->mychatclient"),strona.Length());
   strona = strona.SubString(1,strona.Pos("<->e")-1);

   for (int i = 1; strona.Pos("\n") > 0; i++)                          //przekztalcanie informacji
      {
      strona = strona.SubString(strona.Pos("\n")+1,strona.Length());
      danan = strona.SubString(2,strona.Pos("\n")-2);
      if (danan.Length()>0)
         {
         if (strona.SubString(1,2)=="hA")                            //wczytanie listy nickow / dodanie nicka in
            {
            chatroom("join "+danan.Delete(1,1));
            fn_list_nick_add(danan);                                        //dopisanie nicka do listy
            }

         if (strona.SubString(1,1)=="l")                               //lost connection  / usuniecie nicka
            {
            chatroom("lost "+danan);
            fn_list_nick_del(danan);                                        //usuniecie nicka z listy
            }

         if (strona.SubString(1,1)=="f")                               //quit / usuniecie nicka
            {
            chatroom("quit "+danan);
            fn_list_nick_del(danan);                                        //usuniecie nicka z listy
            }

         if (strona.SubString(1,1)=="g")                               //kick (wystepuje przed quit)
            {
            chatroom("kick "+danan);
            }

         if (strona.SubString(1,2)=="dA")                            //wiadomosci czatowe (pokuj i priv)
            {
            if (danan.Pos("")==5)                                          // rozdzielenie pokuj / priv
               {
               chatroom("msg "+danan);
               }
            else
               {
               chatroom("priv "+danan);
               }
            }

         if (strona.SubString(1,1)=="i")                               //informacje potrzebne do przetwarzania czata
            {
            zmiennai = danan;
            }
         }
      }
   if (Button2->Caption=="Logowanie...")
      {
      Button2->Caption="Rozłącz";
      Button2->Enabled = true ;
      chatroom("in "+Edit2->Text);
      }

   Timer1->Enabled = true;

}

Kod: Zaznacz cały
void __fastcall TForm1::ClientSocket1Read(TObject *Sender,
     TCustomWinSocket *Socket)
{

AnsiString dane = Socket->ReceiveText();                                        //pobranie danych
AnsiString naglowek = dane.SubString(1,dane.Pos("\r\n\r\n")-1);                 //oddzielenie naglowkow od danych
AnsiString strona = dane.Delete(1,dane.Pos("\r\n\r\n")+3);                  //oddzielenie strony od danych

// Obsluga czata w pakietach przychodzacych
if (strona.Pos("<->mychatclient")>0)                                          // warunek iz zostaly pobrane dane dla czata
   {
   obslugaczata(strona);
   }

}


Mam jeszcze male pytanie jezeli w for bede mial warunki if i w nich return; to czy cale for sie zakonczy czy tylko w for sie zrobi przeskok ? czyli ze pominie reszte kodu w for i wroci na poczatek for (kolejny obieg) poniewaz w obslugaczata jest tylko jeden warunek prawdziwy przy kazdym obiegu wiec jak natrafi na poprawny to reszty nie musi wykonywac tylko zaczac od poczatku.
a i jeszcze male pytanko co znaczy __fastcall przed funkcja (mam helpa ale w pelni nie potrafie z niego korzystac :) a raczej nie rozumiem jego opisow)
Avatar użytkownika
ch2_lbn
 
    Windows 7Firefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez Cyfrowy Baron » czwartek, 1 kwietnia 2010, 20:24

Jeżeli funkcję return umieścisz w warunku if to spowoduje ona wyrzucenie z funkcji, czyli dalsza cześć kodu po return się nie wykona.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez Darek_C++ » poniedziałek, 5 kwietnia 2010, 09:38

W tego typu aplikacji jak klient czta musi być metoda która online nasłuchuje/oczekuje danych wysłanych przez serwer po zaistnieniu jakiegoś zdarzenia na czacie. Korzystając z obsługi socketów w BCB mam zadanie ułatwione, bo jest metoda OnRead która właśnie nasłuchuje informacji od serwera do tego IMHO w osobnym wątku.

Wiec nie ma potrzeby wymyślać koła od nowa i obsługi w pętli i osobnym wątku pobierania danych AnsiString odebrane = ClientSocket1->Socket->ReceiveText();, bo dostęp do wysłanych danych mamy w onread. Zatem jeśli serwer wyśle do klienta jakieś dane w OnRead masz od razu do nich dostęp w String odebrane = Socket->ReceiveText();.

Każdy czat ma jakiś protokół wiec w zależności od wystąpienia danego ciągu znaków w zmiennej odebrane wykonujesz dalsze operacje.
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: ClientSocket odbieranie danych bez OnRead

Nowy postprzez Cyfrowy Baron » poniedziałek, 5 kwietnia 2010, 11:37

Od samego początku staram się to uzmysłowić autorowi wątku.

Darek_C++ napisał(a):Każdy czat ma jakiś protokół wiec w zależności od wystąpienia danego ciągu znaków w zmiennej odebrane wykonujesz dalsze operacje.


Dlatego zaproponowałem stworzenie funkcji, która będzie sprawdzała jaki typ danych został odebrany i w zależności od tego prześle to co odebrano do dalszego przetworzenia.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4728
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 444
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Aplikacje sieciowe

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 3 gości

cron