CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - socket wysyłanie jpg

socket wysyłanie jpg

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

Re: socket wysyłanie jpg

Nowy postprzez gregor » niedziela, 10 października 2010, 16:09

Cyfrowy Baron napisał(a):Wziąłem się za analizowanie Twojego projektu z załącznika i już na samym początku wywołał on u mnie rozdrażnienie. Nie stosujesz się do zaleceń, jakie tutaj Tobie podajemy.


Nie chciałem wywołać u Ciebie rozdrażnienia odczytując te poradę od was zamieściłem te zmienne na właściwym miejscu tak jak było w poradzie, ale zmieniłem jej miejsce, bo coś szło nie tak w kodzie jak je wpisywałem i szukając błędu je przemieściłem a wysyłając pliki na forum nie zmieniłem tego i tak zostało.


Dostosowałem się do ty porad odnośnie testowanie i kompilacji.

Sprawdzałem program wysłany przez Ciebie no i rzeczywiście działa. Nie zmienia to faktu iż musze jeszcze się podszkolić i dalej pisać ten program sam bo bez większej wiedzy nawet trudno jest korzystać z porad.

Dzięki za odpowiedzi pozdrawiam
Avatar użytkownika
gregor
Bladawiec
Bladawiec
 
Posty: 17
Dołączył(a): wtorek, 5 października 2010, 18:56
Podziękował : 0
Otrzymał podziękowań: 0
System operacyjny: Win XP
Kompilator: RAD Studio 2010
C++
Gadu Gadu: 0
    Windows XPOpera

Re: socket wysyłanie jpg

Nowy postprzez Cyfrowy Baron » poniedziałek, 11 października 2010, 20:41

Zastanawiałem się trochę nad tym programem i wydaje mi się, że na dłuższą metę to on nie będzie dobrze działał.
Programy SERWER I KLIENT były testowane na jednym komputerze, do tego w sieci lokalnej, więc zarówno SERWER jak i KLIENT pracowały mniej więcej z tą samą prędkością czyli SERWER nadążał z odbieraniem pakietów wysyłanych przez KLIENT'a, a gdy nie nadążał to pakiety były gubione i w efekcie SERWER błędnie zapisywał pliki, lub wogóle ich nie zapisywał. Dzieje się tak wtedy, gdy SERWER wolniej odbiera dane niż KLIENT je wysyła. Pakiety są gubione, gdyż SERWER nie buforuje nigdzie nieodebranych pakietów, gdyż ich nie odebrał, KLIENT również nie wysyła ich do żadnego bufora. Pakiety nie mogą istnieć w próżni, więc te których SERWER nie zdążył odebrać znikają. Po stronie serwera występuje desynchronizacja i pakiety są zapisywane nieprawidłowo.
Wprowadzone przeze mnie opóźnienie po stronie klienta, nie rozwiązuje problemu, a jedynie go ukrywa. Program co prawda działa, ale tylko do czasu, gdy SERWER nadąża odbierać pakiety, gdyż nadchodzą one wolniej, jednak zawsze może się zdarzyć, że SERWER z jakiegoś powodu ulegnie opóźnieniu i nie odbierze jakiegoś pakietu, szczególnie gdy programy będą działały na dwóch różnych komputerach.
Rozwiązanie może być tylko jedno. Programy muszą się ze sobą komunikować, czyli po każdym wysłanym pakiecie - nie pliku, lecz po każdym fragmencie pliku KLIENT powinien czekać na odpowiedź od SERWER'a, że ten pakiet odebrał i po takiej odpowiedzi KLIENT wysyła kolejny pakiet. SERWER po każdym odebranym pakiecie powinien wysłać do klienta informację, że pakiet został odebrany. Nie znam się dobrze na socketach, ale to chyba oznacza, że każdy z tych programów powinien być jednocześnie KLIENT'em i SERWER'em, ponieważ SERWER musi wysłać wiadomość, ale do konkretnego KLIENT'a a KLIENT musi nasłuchiwać tak jak SERWER.
Wydaje mi się, że właśnie tak to powinno się odbywać, ale nie przesądzam sprawy, gdyż mam niepełną wiedzę na temat socket'ów.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: socket wysyłanie jpg

Nowy postprzez polymorphism » poniedziałek, 11 października 2010, 21:22

pakiety są gubione, gdyż SERWER nie buforuje nigdzie nieodebranych pakietów, gdyż ich nie odebrał, KLIENT również nie wysyła ich do żadnego bufora. Pakiety nie mogą istnieć w próżni, więc te których SERWER nie zdążył odebrać znikają. Po stronie serwera występuje desynchronizacja i pakiety są zapisywane nieprawidłowo.

W TCP/IP nie ma takiej opcji. Jeśli adresat nie odbiera danych i ma zapchany bufor, nadawca będzie czekać jakiś czas1) (zwykle jest to kilkanaście/kilkadziesiąt sekund). Po przekroczeniu tego czasu, tzw. timeoutu, połączenie na ogół jest zrywane, choć nie ma reguły.

1)mowa o socketach blokujących

(...) czyli po każdym wysłanym pakiecie - nie pliku, lecz po każdym fragmencie pliku KLIENT powinien czekać na odpowiedź od SERWER'a, że ten pakiet odebrał i po takiej odpowiedzi KLIENT wysyła kolejny pakiet. SERWER po każdym odebranym pakiecie powinien wysłać do klienta informację, że pakiet został odebrany.

Takie potwierdzanie jest zbyteczne, ponieważ zapewnia to model TCP/IP. Jedyne co serwer może potwierdzić to odebranie całego pliku.




--- trochę z opóźnieniem, ale co tam... ----

Drobna korekta ze względu na to, że chodzi o sockety nieblokujące:
KOD cpp:     UKRYJ  
void TForm7::SendExact(const char *p, unsigned size)
{
        while(size)
        {
                int sent = ClientSocket1->Socket->SendBuf(p,size);  
                if(sent == -1)
                {
                        /* socket zapchany, poczekaj chwilę i spróbuj jeszcze raz */
                        Sleep(10);
                        continue;
                }
               
                p += sent;
                size -= sent;
        }
}
 

wtedy to:
Błąd udało mi się wyeliminować, gdy wprowadziłem niewielkie opóźnienie w tej pętli:

nie będzie potrzebne.

Kolejna sprawa, to nie testuj tych programów w środowisku C++Builder, lecz uruchom je normalnie. Ustaw typ kompilacji na Release.
Z tym się zupełnie nie zgodzę. Tryb BEDUG jest właśnie po to, żebyś mógł aplikację testować i śledzić pod debuggerem. A jeśli aplikacja nie działa w tym trybie, to znaczy, że masz błąd, a kompilacja w trybie RELEASE nie rozwiąże go.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: socket wysyłanie jpg

Nowy postprzez Cyfrowy Baron » wtorek, 12 października 2010, 09:19

polymorphism napisał(a):W TCP/IP nie ma takiej opcji. Jeśli adresat nie odbiera danych i ma zapchany bufor, nadawca będzie czekać jakiś czas1) (zwykle jest to kilkanaście/kilkadziesiąt sekund). Po przekroczeniu tego czasu, tzw. timeoutu, połączenie na ogół jest zrywane, choć nie ma reguły.


Z testów które przeprowadziłem na programach wynikało, że klient wysyła pakiety, ale serwer nie wszystkie odbiera, czyli w pewnym momencie jakiś pakiet był gubiony przez serwer i potem już wszystko się sypało, połączenie nie było zrywane. Socket upychał kolejne pakiety do jednego pliku, albo tworzył pliki o rozmiarze zerowym.
W trybie blokującym, różne kombinacje serwer i klient w trybie blokującym, tylko jeden w trybie blokującym, programy wogóle się ze sobą nie komunikowały.
Z tego co piszesz, czyli, że nadawca będzie czekał, wynika, iż serwer jednak komunikuje się z klientem, w przeciwnym razie skąd klient miałby wiedzieć, że serwer ma zapchany bufor.
Zastanawia mnie kwestia bufora. Czy przechowuje ona pakiety wysłane przez klienta, czy tylko informacje, że jakieś pakiety są wysyłane?




polymorphism napisał(a):Drobna korekta ze względu na to, że chodzi o sockety nieblokujące:


To rozwiązanie jest lepsze i teraz wydaje się oczywiste. Gdybym zadał sobie trudu by przeanalizować Twoją funkcję SendExact być może sam bym na to wpadł. Mam tylko jedno zastrzeżenie, otóż opóźnienie jest w zasadzie zbędne, program działa prawidłowo bez tego opóźnienia. Zrezygnowałbym z niego, gdyż sztucznie wydłuża czas oczekiwania z wysłaniem kolejnego pakietu. Co prawda jest to mały interwał czasu, ale w praktyce może być różny. Co najwyżej pętla wykona kilka jałowych obiegów. Zapomniałeś też o rzutowaniu na void.

Pozwolę sobie zamieścić całość działającego kodu, gdyby ktoś kiedyś tego potrzebował, gdyż w takiej formie jak teraz, jest to już do zaakceptowania:

KLIENT
KOD cpp:     UKRYJ  
void TForm7::SendExact(const char *p, unsigned size) /* funkcja autorstwa polymorphism */
{
 while(size)
 {
  int sent = ClientSocket1->Socket->SendBuf( (void *)p, size );

  if(sent == -1) continue;

  p += sent;
  size -= sent;
 }
}
//---------------------------------------------------------------------------
void __fastcall TForm7::Button1Click(TObject *Sender)
{
 ClientSocket1->Active = true;
 Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall ScreenCapture(TMemoryStream *mStream)
{
  std::auto_ptr<TCanvas> pCanvas(new TCanvas());
  std::auto_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap());
  pCanvas->Handle = GetDC(0);
  Bmp->Width  = Screen->Width;
  Bmp->Height = Screen->Height;
  Bmp->Canvas->CopyRect(Rect(0, 0, Bmp->Width, Bmp->Height), pCanvas.get(), Rect(0, 0, Bmp->Width, Bmp->Height));

  std::auto_ptr<TJPEGImage> jpegImg(new TJPEGImage());
  jpegImg->CompressionQuality = 20;
  jpegImg->Assign(Bmp.get());

  jpegImg->SaveToStream(mStream);
  ReleaseDC(0, pCanvas->Handle);
}
//---------------------------------------------------------------------------
void __fastcall TForm7::Timer1Timer(TObject *Sender)
{
 TMemoryStream *mStream = new TMemoryStream();
 ScreenCapture(mStream);

 char bufor[1024];
 mStream->Position = 0;
 long razem = 0, rozmiar = 0 , max = mStream->Size;

 SendExact((char*)&max, sizeof(long));

 while(razem < max)
 {
   rozmiar = mStream->Read(bufor, 1024);
   SendExact(bufor, rozmiar);
   razem += rozmiar;
 }
 delete mStream;
}




polymorphism napisał(a):Z tym się zupełnie nie zgodzę. Tryb BEDUG jest właśnie po to, żebyś mógł aplikację testować i śledzić pod debuggerem. A jeśli aplikacja nie działa w tym trybie, to znaczy, że masz błąd, a kompilacja w trybie RELEASE nie rozwiąże go.


To akurat wiem. Debuger jednak żadnych błędów tutaj nie pokazywał. Napisałem to dlatego, że gregor jak wywnioskowałem z analizy jego projektu, wszystkie aplikacje tworzy w domyślnym trybie DEBUG, nawet aplikacje finalne i nie sądzę, by na obecnym pozimie wiedzy potrafił korzystać z debugowania i CodeGuard. Poza tym mamy tutaj dwa programy i tylko jeden można uruchomić w środowisku. Stworzyłem grupę projektów, ale nie da się debugować obydwu programów na raz. Poza tym gregor nie kompiluje aplikacji razem z bibliotekami, więc wkrótce zgłosi się z problemem uruchamianie jego programu na innych komputerach.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: socket wysyłanie jpg

Nowy postprzez polymorphism » wtorek, 12 października 2010, 10:53

Z testów które przeprowadziłem na programach wynikało (...) programy wogóle się ze sobą nie komunikowały.

Podejrzewam, że to kwestia poprawnego wykorzystania VCL-owych socketów, które domyślnie działają w trybie nieblokującym, czyli wywołanie ReceiveBuf lub SendBuf może nic nie odebrać/wysłać, co się nie zdarza w przypadku socketów blokujących (w każdym razie w winsock'ach). Następna rzecz to to, że samo przełączenie trybu nie wystarcza. Według dokumentacji zamiast wymienionych metod trzeba użyć specjalnego strumienia.

Z tego co piszesz, czyli, że nadawca będzie czekał, wynika, iż serwer jednak komunikuje się z klientem (...)

Tak. Po każdym odebranym pakiecie odbiorca wysyła nadawcy komunikat ACK, który potwierdza odebranie pakietu. Czyli nie ma mowy o gubieniu czegokolwiek.

Zastanawia mnie kwestia bufora. Czy przechowuje ona pakiety wysłane przez klienta, czy tylko informacje, że jakieś pakiety są wysyłane?

Przechowuje pakiety odebrane.

Zrezygnowałbym z niego, gdyż sztucznie wydłuża czas oczekiwania z wysłaniem kolejnego pakietu.

No nie sztucznie, bo po co mam wciskać pakiet, jeśli przed ułamkiem sekundy nie było na niego miejsca? Sensowniej jest odczekać chwilę i znowu spróbować (to opóźnienie ma tylko miejsce w przypadku przepełnionego bufora). Zważ jeszcze to, że jeśli bufor socketa nie będzie na bieżąco opróżniany, bo np. coś z siecią będzie nie tak, pętla będzie ryła do wystąpienia timeoutu, zarzynając CPU (tu pewności nie mam).

Zapomniałeś też o rzutowaniu na void.

Heh, nie tyle ja zapomniałem o rzutowaniu, co panowie od VCL-a zapomnieli dodać const przy wskaźniku w SendBuf. Problemem nie jest rzutowanie char* na void*, bo to jest w pełni legalne i nie wymaga jawnego rzutowania, tylko przypisanie wskaźnika const na wskaźnik non-const. Wszystkie wskaźniki i referencje w parametrach funkcji, które wskazują na obiekty niepodlegające zmianie, powinny być stałe. Takie są zasady dobrego stylu w C++. Panowie nie pierwszy raz dali ciała... :zawiedziony:
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: socket wysyłanie jpg

Nowy postprzez Cyfrowy Baron » wtorek, 12 października 2010, 11:35

Tak. Po każdym odebranym pakiecie odbiorca wysyła nadawcy komunikat ACK, który potwierdza odebranie pakietu. Czyli nie ma mowy o gubieniu czegokolwiek.


A jednak serwer nie odbierał wszystkich pakietów, więc coś musiało się dziać. Co do tej komunikacji, to wcześniej proponowałem zrobić coś podobnego, gdyż nie wiedziałem, że się jednak komunikują. Sądziłem, że klient wysyła pakiety po kolei i nie dba o to, czy serwer odebrał.

No nie sztucznie, bo po co mam wciskać pakiet, jeśli przed ułamkiem sekundy nie było na niego miejsca? Sensowniej jest odczekać chwilę i znowu spróbować (to opóźnienie ma tylko miejsce w przypadku przepełnionego bufora). Zważ jeszcze to, że jeśli bufor socketa nie będzie na bieżąco opróżniany, bo np. coś z siecią będzie nie tak, pętla będzie ryła do wystąpienia timeoutu, zarzynając CPU (tu pewności nie mam).


Co do procesora, to jest wykorzystywany w niewielkim stopniu.
Moja sugestia odnośnie usunięcia opóźnienia, wynikała z tego, że w proponowanym przeze mnie wcześniej rozwiązaniu to opóźnienie występowało przy każdym pakiecie. Nie zwróciłem uwagi na fakt, że u Ciebie występuje ono tylko w sytuacji, gdy serwer nie może pakietu odebrać, więc w praktyce tych opóźnień nie będzie wiele.

Heh, nie tyle ja zapomniałem o rzutowaniu, co panowie od VCL-a zapomnieli dodać const przy wskaźniku w SendBuf.


Niemniej jednak jest tutaj potrzebne.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: socket wysyłanie jpg

Nowy postprzez polymorphism » wtorek, 12 października 2010, 12:45

A jednak serwer nie odbierał wszystkich pakietów, więc coś musiało się dziać.

Tak jak pisałem, wynikało to ze złego użycia VCL-owych socketów. Pierwotna wersja SendExact nie uwzględniała tego, że bufor socketa może być przepełniony, wszak była pisana pod sockety blokujące. Choć przyznam, że nie bardzo rozumiem, w jaki sposób te pakiety miałyby być gubione :o Jeśli SendBuf zwracałoby -1, to size by rosła, wskaźnik p byłby cofany. Czyli w najlepszym przypadku powinno dojść do wysłania zawartości, która już została wysłana. W najgorszym - do błędu dostępu do pamięci, ponieważ wskaźnik p został za bardzo przewinięty do tyłu. Hmm, jeśli to gubienie pakietu było następstwem przerwanego połączenia, wtedy wszystko by mi się zgadzało...
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: socket wysyłanie jpg

Nowy postprzez Cyfrowy Baron » wtorek, 12 października 2010, 14:47

Nie jestem pewien czy to efekt gubienia pakietów, czy raczej coś w rodzaju desynchronizacji serwera z klientem. W praktyce to wyglądało tak, że np. serwer odebrał 8 plików prawidłowo, 9 plik był niekompletny, brakowało np. końcówki, 10 plik był wogóle nieczytelny, a jego rozmiar równał się wszystkim pakietom wysłanym przez klienta od niepełnej końcówki 9 pliku. Czyli niekoniecznie jakiś pakiet został zagubiony, lecz raczej coś się pomieszało w pakietach i od pojawienia się błędu wszystkie pakiety były ładowane do jednego pliku.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Poprzednia strona

  • 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 1 gość