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..

socket wysyłanie jpg

Nowy postprzez gregor » wtorek, 5 października 2010, 19:02

Witam

Szukałem tego w poradach ale nie znalazłem więc piszę do was z prośbą o napisanie przykładowego kodu z ServerSocket i ClientSocket gdzie ClientSocket wysyła zdjecie.jpg do ServerSocket
Wiem, że te zdjęcie trzeba wysyłać podzielone ale mam problem z wysłaniem tego i odebraniem podzielonego zdjęcia. Będę wdzięczny za przykładowy kod.

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 MisticFrezer » wtorek, 5 października 2010, 23:05

Ja bym plik .jpg otworzył binarnie i kawałek po kawałku czytał (np 1024 bajtów) i takie kąski wysyłałbym via sockety. Serwer by sobie złozył plik do kupy i już!
Tak samo sie pobiera i wysyła pliki z/do internetu, gdy chcesz mieć np. pasek postępu, albo nie ma gotowej funkcji.
Avatar użytkownika
MisticFrezer
Bladawiec
Bladawiec
 
Posty: 23
Dołączył(a): wtorek, 23 lutego 2010, 23:57
Lokalizacja: Wrocław
Podziękował : 1
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP3, Windows 7 Pro
Kompilator: BCB6, RAD Studio 2010, VS 2010
Gadu Gadu: 0
    Windows XPOpera

Re: socket wysyłanie jpg

Nowy postprzez gregor » środa, 6 października 2010, 13:16

MisticFrezer napisał(a):Ja bym plik .jpg otworzył binarnie


Za bardzo nie wiem jak to ugryźć.

ServerSocket i ClientSocket pierwsze starcie :)

Pod spodem zamieściłem taki kod, co w zasadzie działa poprawnie, ale z jedna wadą plik przesłany nie nadaje się do edycji do póki nie zostanie zamknięty program z serwerem. Próbowałem temu zaradzić zamykając procesy i resetując zmienne (to widać w kodzie „serwer //zamykanie, konczenie”)

Ale coś mi nie wychodzi może ktoś z was wie jak zamknąć przesłany plik albo w czym jest błąd?

KOD cpp:     UKRYJ  
BOOL przesyl = false;
TFileStream *fl;
int max = 0;
char* bufor = new char[1024];


Serwer:
KOD cpp:     UKRYJ  
void __fastcall TForm3::ServerSocket1ClientRead(TObject *Sender, TCustomWinSocket *Socket)
{

int max=0;
int size=0;
if (przesyl)
{
char* buf = new char[256];
size = Socket->ReceiveBuf(buf,256);
fl->WriteBuffer(buf,size);
}
else
{
Socket->ReceiveBuf(&max,4);
Caption = IntToStr(max);
fl = new TFileStream("C:\\222.jpg", fmCreate);
przesyl = true;
}

  //zamykanie, konczenie
  if(size==max)
  {
  size=0; max=0; przesyl = false; delete fl;
  }

}


klient:
KOD cpp:     UKRYJ  
void __fastcall TForm4::Button4Click(TObject *Sender)
{
TFileStream *fl = new TFileStream("111.jpg", fmOpenRead);
int razem = 0, rozmiar = 0 , max = fl->Size;
ClientSocket1->Socket->SendBuf(&max,4);

do
{
rozmiar = fl->Read(bufor,1024);
razem+=rozmiar;
ClientSocket1->Socket->SendBuf(bufor,rozmiar);
Sleep(1);
Application->ProcessMessages();
} while (razem<max);

}
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 » środa, 6 października 2010, 14:47

Nie możesz go używać ponieważ obiekt klasy TFileStream wciąż używa tego pliku, dlatego musisz zamknąć strumień czyli np. delete f1:

KOD cpp:     UKRYJ  
void __fastcall TForm4::Button4Click(TObject *Sender)
{
  TFileStream *fl = new TFileStream("111.jpg", fmOpenRead);
  int razem = 0, rozmiar = 0 , max = fl->Size;
  ClientSocket1->Socket->SendBuf(&max,4);

  do
  {
    rozmiar = fl->Read(bufor,1024);
    razem += rozmiar;
    ClientSocket1->Socket->SendBuf(bufor,rozmiar);
    Application->ProcessMessages();
  } while (razem < max);

 delete f1;
}


To Sleep(1) jest zbędne, gdyż teoretycznie wstrzymuje aplikację na jedną milisekundę (1/1000), czyli w zasadzie wystarczy sama funkcje Application->ProcessMessages() do odświeżenia kolejki komunikató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 Cyfrowy Baron » środa, 6 października 2010, 15:02

W zdarzeniu ServerSocket1ClientRead jest błąd. Jeżeli deklarujesz obiekt klasy TFileStream poza tym zdarzeniem, to jest to obiekt prywatny, publiczny lub globalny, więc nie możesz go niszczyć w tym zdarzeniu, gdyż może to prowadzić do wycieku pamięci. Proponuje tworzyć i niszczyć ten obiekt wewnątrz tego zdarzenia.
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 Cyfrowy Baron » środa, 6 października 2010, 15:30

Dodam może jeszcze, że jeżeli chcesz używać globalnego obiektu typu TFileStream, to nie możesz zamykać strumienia poprzez delete, gdyż ta funkcja niszczy obiekt, musisz raczej zamykać plik:

KOD cpp:     UKRYJ  
  FileClose(f1->Handle);
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 gregor » środa, 6 października 2010, 17:21

Teraz działa dobrze kod został zmieniony w serwer. Jest jednak błąd przy ponownym przesłaniu pliku, on występuje nawet wtedy gdy usunę poprzednio przesłany plik ze zdjęciem. Dopiero ponowne uruchomienie serwera pozwala ponownie przesłać plik.
Przy ponownym przesłaniu pliku aplikacja z serwerem daje mi błąd:
Stream write error.

KOD cpp:     UKRYJ  
BOOL przesyl = false;
TFileStream *fl;
int max = 0;
char* bufor = new char[8192];
long wielkoscpliku,odebranowszystko ;
KOD cpp:     UKRYJ  
//Serwer:

void __fastcall TForm3::ServerSocket1ClientRead(TObject *Sender, TCustomWinSocket *Socket)
{

if (przesyl){
char* buf = new char[1024];
int size = Socket->ReceiveBuf(buf,1024);
fl->WriteBuffer(buf,size);
odebranowszystko += size;
}
else
{
fl = new TFileStream("C:\\222.jpg", fmCreate);
przesyl = true;
Socket->ReceiveBuf(&wielkoscpliku,sizeof(long));
}
  if(odebranowszystko == wielkoscpliku) fl->Free();

}

KOD cpp:     UKRYJ  
//Klient:

void __fastcall TForm4::Button4Click(TObject *Sender)
{
                //fl->WriteBuffer(buf,size);
  TFileStream *fl = new TFileStream("111.jpg", fmOpenRead);
  int razem = 0, rozmiar = 0 , max = fl->Size;
  ClientSocket1->Socket->SendBuf(&max,sizeof(int));
  //ClientSocket1->Socket->SendBuf(&max,4);
  //ProgressBar1->Max = max;

  do
  {
        rozmiar = fl->Read(bufor,1024);
        razem += rozmiar;
        ClientSocket1->Socket->SendBuf(bufor,rozmiar);
        Application->ProcessMessages();
        //ProgressBar1->StepBy(rozmiar);
  } while (razem < max);

 delete fl;

}
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 gregor » środa, 6 października 2010, 17:43

No teraz działa wszystko trzeba zresetować zmienne w serwer:
KOD cpp:     UKRYJ  
         if(odebranowszystko == wielkoscpliku)  {
         fl->Free();
         size=0;
         odebranowszystko=0;
         przesyl = false;
         }
Dzięki za pomoc Pozdrawiam

PS
Nie wiem czy to jest praktykowane ale można by to dodać do „TEMATYCZNY SPIS PORAD”
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 » środa, 6 października 2010, 19:46

Nie wiem na jak długo będzie to Tobie działać, gdyż funkcja Free() daje niemal taki sam efekt jak delete. Dla globalnego obiektu typu TFileStream podałem funkcję FileClose i to jej powinieneś używać do uwalniania pliku.

Błąd wywołuje raczej ten fragment kodu:

KOD cpp:     UKRYJ  
fl = new TFileStream("C:\\222.jpg", fmCreate);


definiujesz obiekt globalny wielokrotnie wewnątrz jednego zdarzenia, co w pewnych okolicznościach prowadzi do wycieku pamięci.
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 gregor » środa, 6 października 2010, 20:01

Cyfrowy Baron napisał(a):Nie wiem na jak długo będzie to Tobie działać, gdyż funkcja Free() daje niemal taki sam efekt jak delete. Dla globalnego obiektu typu TFileStream podałem funkcję FileClose i to jej powinieneś używać do uwalniania pliku.

Ok. zrobione FileClose(fl->Handle);


Cyfrowy Baron napisał(a):Błąd wywołuje raczej ten fragment kodu:

KOD cpp:     UKRYJ  
fl = new TFileStream("C:\\222.jpg", fmCreate);


definiujesz obiekt globalny wielokrotnie wewnątrz jednego zdarzenia, co w pewnych okolicznościach prowadzi do wycieku pamięci.


no ale jak to zastąpić, albo zakończyć po wysłaniu?
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 » środa, 6 października 2010, 20:09

Zamiast klasy TFileStream proponuję użyć prostszych funkcji, może tak:

KOD cpp:     UKRYJ  
String  fileName = "c:\\nazwa_pliku";

BOOL przesyl = false;
int max = 0;
char* bufor = new char[8192];
long wielkoscpliku, odebranowszystko;

//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
        TCustomWinSocket *Socket)
{
  int oHandle, cHandle, size;
  if(przesyl)
  {
   char* buf = new char[1024];
   size = Socket->ReceiveBuf(buf, 1024);

   oHandle = FileOpen( fileName, fmOpenReadWrite);
   FileWrite(oHandle, buf, size);

   odebranowszystko += size;
   FileClose(oHandle);
  }
  else
  {

   cHandle = FileCreate("C:\\222.jpg", fmCreate);
   przesyl = true;
   Socket->ReceiveBuf(&wielkoscpliku, sizeof(long));
  }

  if(odebranowszystko == wielkoscpliku)
  {
   FileClose(cHandle);
   size = 0;
   odebranowszystko = 0;
   przesyl = false;
  }
}


Jak widzisz nie trzeba deklarować globalnego obiektu klasy TFileStream, więc nie ma problemu z wyciekiem pamięci. Zwalanie jest proste poprzez uchwyty. Zamiast funkcji WriteBuffer użyłem funkcji FileWrite, która to funkcja zapisuje dane od razu do pliku, pierwszy parametr (Handle) to uchwyt do pliku pobrany za pomocą funkcji FileOpen lub FileCreate, drugi to dane, które zostaną zapisane do pliku. Trzeci to ilość danych, które mają być zapisane.

Poeksperymentuj z tymi funkcjami, a jeżeli zdecydujesz się jednak na klasę TFileStream, to skonstruuj ja tak by nie używać globalnego obiektu tej klasy.
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 gregor » środa, 6 października 2010, 21:16

Teraz to się zakręciłem :D

Napisałeś zmieniony kod dla programu serwer a czy dla klienta też zmieniać?


Sprawdziłem ten kod i na wyjściu daje mi plik 0 bajtór dlaczego?
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 » czwartek, 7 października 2010, 09:43

Pokazałem Tobie jedną z możliwości, gdyż to co robisz z globalnym obiektem klasy TFileStream wywołuje błędy. Dlaczego? Dlatego, że ta *klasa otwiera plik gdy jest tworzona i nie ma posiada funkcji, która pozwalała by ponownie w tej samej *klasie otworzyć drugi plik. Gdy więc w zdarzeniu ServerSocket1ClientRead definiujesz tą *klasę, a potem ją niszczysz, to ten obiekt poza tym zdarzeniem i tak nie istnieje, więc nigdzie indziej nie możesz go użyć. Niebezpieczeństwo takiego rozwiązania polega na tym, że w zdarzeniu ServerSocket1ClientRead ten obiekt jest wielokrotnie definiowany, za każdym razem gdy to zdarzenie jest wywoływane. W wyniku tego powstają nowe obiekty tej *klasy, a stare zostają porzucone. By to mgło działać, przed każdą definicją obiektu tej *klasy musiałbyś najpierw zniszczyć stary obiekt. Po zamknięciu takiego globalnego obiektu również nie możesz w nim ponownie otworzyć pliku, gdyż ta klasa w ten sposób nie działa. Dlatego możesz tworzyć ten obiekt w zdarzeniu ServerSocket1ClientRead dokładnie tak samo jak to robisz w zdarzeniu Button4Click, gdzie tworzysz obiekt wewnątrz zdarzenia i wewnątrz tego zdarzenia go niszczysz. Takie rozwiązanie wymaga zniszczenia obiektu, gdy nie jest już potrzebny i zawsze trzeba o tym pamiętać. Inne rozwiązanie to użycie funkcji FileOpen - do otwarcia istniejącego już pliku, FileCreate do utworzenia pliku, FileWrite do zapisywania danych do pliku, przy czym jako pierwszy argument podajesz uchwyt do pliku otwartego za pomocą funkcji FileOpen lub FileCreate, FileRead do czytania z pliku na zasadzie podobnej do funkcji FileWrite.
Jeszcze inny sposób to użycie globalnego, prywatnego, publicznego lub lokalnego obiektu typu TMemoryStream. Plik będzie najpierw zapisywany w pamięci, a potem można go zapisać do pliku. Jak zapewne się domyślasz zapisanie w pamięci ma tą wadę, że w przypadku dużych plików, komputer musi posiadać wymaganą ilość pamięci.


gregor napisał(a):Sprawdziłem ten kod i na wyjściu daje mi plik 0 bajtów dlaczego?


Nie wiem dlaczego, gdyż nie do końca rozumiem do czego używałeś globalnego obiektu klasy TFileStream w zdarzeniu ServerSocket1ClientRead. Założyłem więc, że ten obiekt na początku otwiera jakiś plik i dlatego użyłem funkcji FileOpen:

KOD cpp:     UKRYJ  
   oHandle = FileOpen( fileName, fmOpenReadWrite);
   FileWrite(oHandle, buf, size);


Jeżeli jednak nie chodzi o otwarcie pliku, to należy użyć funkcji FileCreate.

Myślę, że problem bierze się z tego, iż plik jest zamykany po każdym odebranym pakiecie, gdyż masz tam funkcję FileClose:


KOD cpp:     UKRYJ  
  if(przesyl)
  {
   char* buf = new char[1024];
   size = Socket->ReceiveBuf(buf, 1024);

   oHandle = FileOpen( fileName, fmOpenReadWrite);
   FileWrite(oHandle, buf, size);

   odebranowszystko += size;
   FileClose(oHandle);  // <-- tutaj
  }


Ponieważ nie zapisujesz całego pliku od razu, lecz w kawałkach to plik powinien zostać zamknięty dopiero po wpisaniu wszystkich danych. Problem w tym zdarzenie ServerSocket1ClientRead zawiera kod, którego przeznaczenie nie jest dla mnie całkiem zrozumiałe, gdyż z jednej strony odwołujesz się do istniejącego pliku, a z drugiej tworzysz nowy plik. By lepiej zrozumieć zaproponowane przeze mnie funkcje powinieneś uświadomić sobie, że każda z tych funkcji zwraca uchwyt do zmiennej typu int. Funkcje FileWrite, FileRead i FileClose komunikują się z funkcjami FileOpen, FileCreate poprzez ten uchwyt, więc operując na jednym pliku powinieneś używać jednego uchwytu i zwalniać go poprzez funkcje FileClose(int Handle), po zakończeniu operacji na pliku.

W Twoim kodzie niezrozumiałe jest dla mnie przeznaczenie tych elementów:

KOD cpp:     UKRYJ  
  if(przesyl)
  {
   char* buf = new char[1024];
   size = Socket->ReceiveBuf(buf, 1024);

   oHandle = FileOpen( fileName, fmOpenReadWrite);
   FileWrite(oHandle, buf, size);

   odebranowszystko += size;
   FileClose(oHandle);
  }
  else
  {

   cHandle = FileCreate("C:\\222.jpg", fmCreate);
   przesyl = true;
   Socket->ReceiveBuf(&wielkoscpliku, sizeof(long));
  }


co w Twoim kodzie wyglądało tak:

KOD cpp:     UKRYJ  
if (przesyl){
char* buf = new char[1024];
int size = Socket->ReceiveBuf(buf,1024);
fl->WriteBuffer(buf,size);
odebranowszystko += size;
}
else
{
fl = new TFileStream("C:\\222.jpg", fmCreate);
przesyl = true;
Socket->ReceiveBuf(&wielkoscpliku,sizeof(long));
}


gdyż z jednej strony odwołujesz się do istniejącego pliku, a z drugiej tworzysz nowy i dlaczego decyduje o tym zmienna przesyl?! Co ta zmienna ma wspólnego z istniejącym plikiem.



*Obiekt klasy TFileStream
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 » czwartek, 7 października 2010, 09:59

Cieknie Wam z tych kodów - nigdzie nie zwalniacie buf. W zasadzie nie widzę sensu tworzenia tego bufora na stercie...
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 » czwartek, 7 października 2010, 10:03

Rzeczywiście! Tak się skupiłem na TFileStream, że na to wogóle nie zwróciłem uwagi, a w zasadzie wystarczy zamiast: char *buf = new char[1024] użyć char buf[1024] i będzie trzeba niczego zwalniać.
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

Następna 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 2 gości