[WinSock] transfer plików

0

Piszę sobię prosty programik do przesyłania plików. Na początek chciałem przesłać 1 "na sztywno" zadeklarowany plik *.jpg.

Serwer mam działający dobrze, sprawdzałem różnymi aplikacjami i działa. Odbiera dane i rozsyła do wszystkich połączonych klientów.

I na początku chciałem spróbować z 2 klientami:

Wysyłanie:

#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <fstream.h>
#include <conio.h>

using namespace std;


int main()
{
	WSAData wsa;
	SOCKET s1;
	struct sockaddr_in addr1;
	  char bufor[999999];

   
    int addrlen;
 

      

fstream plik;
    char *dane;
    int dlugosc;

  plik.open("obraz.jpg",ios::in|ios::binary);
  plik.seekg(0,ios::end);
  dlugosc=plik.tellg();
  dane=new char[dlugosc];
  plik.seekg(0,ios::beg);
  plik.read(dane,dlugosc);
  plik.close();
  cout<<"Wczytalem plik"<<endl;

	if(WSAStartup(MAKEWORD(2,0),&wsa)==SOCKET_ERROR)
	{
	    cout<<WSAGetLastError()<<endl;
	    WSACleanup();
	}
	else
	{
	    cout<<"WSA ready."<<endl;
	}

	 s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    struct hostent *host;
    host=gethostbyname("127.0.0.1");
    memset( &addr1, 0, sizeof addr1 );
    addr1.sin_family = AF_INET;
    addr1.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
    addr1.sin_port = htons(1337);
    if(connect(s1,(struct sockaddr *) &addr1, sizeof(addr1))==SOCKET_ERROR)
    {
        cout<<WSAGetLastError()<<endl;
        WSACleanup();
    }
    else
    {
        cout<<"Connected"<<endl;
    }
    cout<<"wcisnij cos!"<<endl;
    getch();
    itoa(dlugosc,bufor,10);
    send(s1,bufor,sizeof(bufor)+1,0);
    send(s1,dane,dlugosc,0);
    cout<<"Wyslalem plik"<<endl;


system("PAUSE");
return 0;
}

A Dobieranie tak:

#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <fstream.h>
#include <cstdlib>

using namespace std;


int main()
{
	WSAData wsa;
	SOCKET s1;
	struct sockaddr_in addr1;

	  char *bufor;
	
 

fstream plik2;
plik2.open("plik.jpg",ios::out|ios::binary);
    int dlugosc;


	if(WSAStartup(MAKEWORD(2,0),&wsa)==SOCKET_ERROR)
	{
	    cout<<WSAGetLastError()<<endl;
	    WSACleanup();
	}
	else
	{
	    cout<<"WSA ready."<<endl;
	}

	 s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    struct hostent *host;
    host=gethostbyname("127.0.0.1");
    memset( &addr1, 0, sizeof addr1 );
    addr1.sin_family = AF_INET;
    addr1.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
    addr1.sin_port = htons(1337);
    if(connect(s1,(struct sockaddr *) &addr1, sizeof(addr1))==SOCKET_ERROR)
    {
        cout<<WSAGetLastError()<<endl;
        WSACleanup();
    }
    else
    {
        cout<<"Connected"<<endl;
    }

    recv(s1,buf,sizeof(buf)+1,0);
    dlugosc=atoi(buf);
    
bufor=new char[dlugosc];
        recv(s1,bufor,dlugosc,0);
 



plik2.write(bufor,dlugosc);
plik2.close();


    cout<<"Zapisalem obraz"<<endl;


system("PAUSE");
return 0;
}

Problem w tym, że nie za bardzo mi to działa. Łącze się z serwerem, wielkość pliku wysyła się niby poprawnie, ale sam plik coś nie chce...
Wie ktoś gdzie leży błąd?

Wybaczcie tragiczny kod i brak wcięć :-/

0

poczytaj dokladnie o recv
http://msdn2.microsoft.com/en-us/library/ms740121.aspx

niekoniecznie musi zwrocic tyle ile jest w bufor (czytal bym do chwili odebrania odpowiedniej ilosci bajtow) - patrz co zwraca recv

0

Hmm... fakt, masz rację. No i trochę to poprawiłem, teraz odbiera chyba plik do końca, bo odebrany plik zajmuje tyle co wysłany, ale nic w nim nie ma, tzn nie ma obrazu. Podejrzewam, że coś nie tak z zapisem jest...

int odebrano;

...

       do
        {
        odebrano=recv(s1,bufor,dlugosc,0);
    } while( odebrano > 0 );
    plik2.write(bufor,dlugosc);
     plik2.close();


    cout<<"Zapisalem obraz"<<endl;

Mniej więcej tak to wygląda...

Edit//

Co jeszcze dziwniejsze, otworzyłem plik odebrany notatnikiem i plik wysłany i są od siebie inne... Nie mam pojęcia dlaczego. Czyżby nie wszystko się wysłało? Jak bez wysyłania otworzę w ten sposób plik i zapiszę to wszystko jest OK. Nie wiem już co myśleć :/

Edit2//

Zamiast obrazka wysłałem plik tekstowy:

oto testowy przesyl

W otrzymanym pliku mam:

rzesyloto testowy p

Wyraźnie widać, że się pakiety coś mieszają... Jak temu zapobiec?

0
do
        {
        odebrano=recv(s1,bufor,dlugosc,0);
    } while( odebrano > 0 );
    plik2.write(bufor,dlugosc);

pomysl..... nie dokonca to jeszcze

do
        {
        odebrano=recv(s1,bufor,dlugosc,0);
    plik2.write(bufor,odebrano);
    } while( odebrano > 0 );

dalej mozna (nie sprawdzam mniej wiecej idea) .. plik moze miec zero bajtow :)

        odebrano=recv(s1,bufor,dlugosc,0);
       while( odebrano > 0 ) {
    plik2.write(bufor,odebrano);
        odebrano=recv(s1,bufor,dlugosc,0);
    } 

0

Hmm nie do końca rozumiem to co napisałeś, jednak spróbowałem tak:

odebrano=recv(s1,bufor,dlugosc,0);
       while( odebrano > 0 )
        {
    plik2.write(bufor,odebrano);
        odebrano=recv(s1,bufor,dlugosc,0);
    }

Nie wiem czy o takie rozwiązanie Ci chodziło, jednak to jest całkiem nie tak, bo nie dość, że plik odebrany jest jakieś 900razy większy to i pusty :P

Edit//
W sumie to nie pusty bo na samym dole jest cała masa jakiegoś śmiecia, ale na końcu jest poprawny tekst, który przesyłam. Teraz tylko, skąd się te śmieci biorą...

0

idea jest taka:

  1. masz bufor

  2. odbierasz do niego dane (sa zapisane od poczatku bufora do odebrane)

  3. zapisujesz bufor do pliku

  4. ofset pliku sie przesuwa (to automat - na konec )

  5. wracamy do pkt 2

0

No OK, już rozumiem i wydaje mi się, że to dobra idea i powinno działać jak ta lala, a jednak nie... Skąd się biorą te "syfy" w pliku?

0

chech slepota ze mnie .... popatrzylem tylko na recv a gdzie w serwerze bind i listen ?

popatrz (podstawy), twoj serwer nie nasluchuje ...
http://www.codeproject.com/internet/winsockintro01.asp

0

Nie nie, żadna z tych aplikacji, których kody tutaj są nie jest serwerem!
Serwer mam oddzielny, napisałem sobie go tak porządniej i testuje na nim wszystko inne. I o ile serwer napisać potrafię to z klientem mam problem. Tutaj w tym przypadku rozdzieliłem klienta na dwie części żeby łatwiej było na początku. Jeden z tych klientów wysyła, a drugi odbiera.

Offtop//
Zna ktoś może jakąś książkę o programowaniu sieciowym w Windows?

0

dobre na poczatek

PISANIE PROGRAMOW INTERNETOWYCH
SOPALA A.
http://www.mareno.pl/prod/MIDN/83-7279-003-5

ps. moze jednak cos w serwerze nie tak ??? skoro dobiera wiecej niz potrzeba ....

0

Nie no serwer zdaje się być OK. Hm spróbuję jeszcze raz to wszystko przepisać, na nowo i dokładniej, może coś poprawię w międzyczasie.
Tymczasem dziękuję za pomoc! :)

P.S. Ta książka chyba jest o Javie, a mi chodzi o C++, przepraszam, że nie sprecyzowałem.

0

Nie jest o javie w 99.9% w c/c++ a na koncu o javie (ostatnie 30 stron z 400 che che czyli w okolo 93% o c/c++).

a problem jest tu (teraz wiem jaki miales zamysl ...)

send(s1,bufor,sizeof(bufor)+1,0);

bufor to tablica

char bufor[999999];

kopiujesz do bufor wielkosc, ale sizeof bedzie rowne 999999 + 1 :)
lepiej strlen(bufor).

//male poprawki - czyscilem klawiature wiec co drugi guzik niedziala ... che che jak zawsze po sprzataniu

0

Tak! teraz już wszystko jest w porządku! Dziękuję Ci bardzo :)
Ech, ale ja jestem bezmyślny, nadal bym nad tym siedział...

0
.Dexter. napisał(a)

Piszę sobię prosty programik do przesyłania plików. Na początek chciałem przesłać 1 "na sztywno" zadeklarowany plik *.jpg.

Serwer mam działający dobrze, sprawdzałem różnymi aplikacjami i działa. Odbiera dane i rozsyła do wszystkich połączonych klientów.

I na początku chciałem spróbować z 2 klientami:

Wysyłanie:

#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <fstream.h>
#include <conio.h>

using namespace std;


int main()
{
	WSAData wsa;
	SOCKET s1;
	struct sockaddr_in addr1;
	  char bufor[999999];

   
    int addrlen;
 

      

fstream plik;
    char *dane;
    int dlugosc;

  plik.open("obraz.jpg",ios::in|ios::binary);
  plik.seekg(0,ios::end);
  dlugosc=plik.tellg();
  dane=new char[dlugosc];
  plik.seekg(0,ios::beg);
  plik.read(dane,dlugosc);
  plik.close();
  cout<<"Wczytalem plik"<<endl;

	if(WSAStartup(MAKEWORD(2,0),&wsa)==SOCKET_ERROR)
	{
	    cout<<WSAGetLastError()<<endl;
	    WSACleanup();
	}
	else
	{
	    cout<<"WSA ready."<<endl;
	}

	 s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    struct hostent *host;
    host=gethostbyname("127.0.0.1");
    memset( &addr1, 0, sizeof addr1 );
    addr1.sin_family = AF_INET;
    addr1.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
    addr1.sin_port = htons(1337);
    if(connect(s1,(struct sockaddr *) &addr1, sizeof(addr1))==SOCKET_ERROR)
    {
        cout<<WSAGetLastError()<<endl;
        WSACleanup();
    }
    else
    {
        cout<<"Connected"<<endl;
    }
    cout<<"wcisnij cos!"<<endl;
    getch();
    itoa(dlugosc,bufor,10);
    send(s1,bufor,sizeof(bufor)+1,0);
    send(s1,dane,dlugosc,0);
    cout<<"Wyslalem plik"<<endl;


system("PAUSE");
return 0;
}

A Dobieranie tak:

#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <fstream.h>
#include <cstdlib>

using namespace std;


int main()
{
	WSAData wsa;
	SOCKET s1;
	struct sockaddr_in addr1;

	  char *bufor;
	
 

fstream plik2;
plik2.open("plik.jpg",ios::out|ios::binary);
    int dlugosc;


	if(WSAStartup(MAKEWORD(2,0),&wsa)==SOCKET_ERROR)
	{
	    cout<<WSAGetLastError()<<endl;
	    WSACleanup();
	}
	else
	{
	    cout<<"WSA ready."<<endl;
	}

	 s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    struct hostent *host;
    host=gethostbyname("127.0.0.1");
    memset( &addr1, 0, sizeof addr1 );
    addr1.sin_family = AF_INET;
    addr1.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
    addr1.sin_port = htons(1337);
    if(connect(s1,(struct sockaddr *) &addr1, sizeof(addr1))==SOCKET_ERROR)
    {
        cout<<WSAGetLastError()<<endl;
        WSACleanup();
    }
    else
    {
        cout<<"Connected"<<endl;
    }

    recv(s1,buf,sizeof(buf)+1,0);
    dlugosc=atoi(buf);
    
bufor=new char[dlugosc];
        recv(s1,bufor,dlugosc,0);
 



plik2.write(bufor,dlugosc);
plik2.close();


    cout<<"Zapisalem obraz"<<endl;


system("PAUSE");
return 0;
}

Problem w tym, że nie za bardzo mi to działa. Łącze się z serwerem, wielkość pliku wysyła się niby poprawnie, ale sam plik coś nie chce...
Wie ktoś gdzie leży błąd?

Wybaczcie tragiczny kod i brak wcięć :-/

0

recv i send daj w pętlę while. W ten sposób:

while(send(argumenty) == SOCKET_EROR);

analogiczne recv. jeśli pętla się zakończy, znaczy, że dane zostały wysłane/odebrane poprawnie

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