Dateien versenden in C++

11/05/2010 13:07 Shadow992#1
Mein problem liegt im Grunde nur darin, dass in der Datei auch "NUL"s enthalten sind. Da die meisten Funktionen Null aber als End Of String kennen, gab es teilweise schon Probleme beim auslesen der Datei, habe es dann aber so gelöst:
PHP Code:
    FILE pFile;
    
pFile fopen (file.c_str(), "rb" ); 
    
string buf;
    
char c;
    do
    {
        
cfgetc (pFile);
        if (!
feof(pFile)) buf+=c;
    } while (!
feof(pFile));
    
fclose (pFile); 
Dadurch wird zumindest die Datei ohne Probleme ausgelesen.
Problem scheint entweder das Empfangen oder das Schreiben zu machen.

Code :
PHP Code:
void Send_Data(char *ip,std::string file)
{
    
SOCKET sSocket;
    
int res ;
    
FILE pFile;
    
long lSize;
    
char buffer;
    
std::string buf;
    
size_t result;

    
pFile fopen (file.c_str(), "rb" );

    
char c;
    do
    {
        
cfgetc (pFile);
        if (!
feof(pFile)) buf+=c;
    } while (!
feof(pFile));

    
fclose (pFile);

    
SOCKADDR_IN service;
    
service.sin_family AF_INET;
    
service.sin_port htons12749 );
    
service.sin_addr.s_addr inet_addr(ip);

        
sSocket socketAF_INETSOCK_STREAM);
        
connectsSocket, (SOCKADDR *)(&service), sizeof(SOCKADDR_IN) );
        
sendsSocketbuf.c_str(), buf.length(), );
        
sendsSocket"[Ende]"6);

    
delete [] buffer;

PHP Code:
void Get_Data()
{
    
SOCKET sSocket;
    
SOCKET connectedSocket;
    
int res ;
    
FILE pFile;
    
long lSize;
    
char buffer;
    
std::string buf;
    
size_t result;
    
SOCKADDR_IN service;

    
sSocket socketAF_INETSOCK_STREAM);

    
buffer = (char*) malloc (sizeof(char)*100001);

    
memset(&service,0,sizeof(SOCKADDR_IN));
    
service.sin_family AF_INET;
    
service.sin_port htons12749 );
    
service.sin_addr.s_addr ADDR_ANY;

    
long rc=bind(sSocket,(SOCKADDR*)&service,sizeof(SOCKADDR_IN));
    
rc=listen(sSocket,10);
    
connectedSocket=accept(sSocket,NULL,NULL);

    
std::string temp,temp2;
    while (
1)
    {
        
temp2="";
        while (
temp2!="[Ende]")
        {
            
res recvconnectedSocketbuffer1000000);
            
temp2=buffer;
            if (
temp2=="[Ende]") break;
            else if (
temp2.find("[Ende]")!=std::string::npos)
            {
                break;
                
temp+=buffer;
                
temp=ReplaceAll(temp,"[Ende]","");
            }
            else 
temp+=buffer;
        }
        if (
res!=SOCKET_ERROR)
        {
            
pFile fopen ("C:\\piccom.bmp""wb" );
            
fwrite(buffer,1,res+1,pFile);
            
fclose (pFile);
        }
        else
        {
            
connectedSocket=accept(sSocket,NULL,NULL);
        }
    }
    
delete [] buffer;

WsaStartUp wird natürlich vor dem Aufruf der Funktionen gestartet.
Es wird auch etwas empfangen, aber teilweise fehlen Zeichen o.ä.

P.S.
Ich weiß, dass es kein "richtiges" C++ ist, da ich auch gleich fstream usw. benutzen könnte.
Mir ist fopen und ähnliches aber lieber. ;)
11/05/2010 15:27 MrSm!th#2
1. Nur die File Funktionen sehen 0 als Ende
Loesung: Stell den Mode auf Binary/nutze nicht die formatierenden Funktionen, sondern die, die einfach die Daten schreiben, ohne sie als Text zu interpretieren und formatieren oder nimm WinApi


Die Socket Funktionen beachten Nullen eh nicht.
Ich wuerde sagen, es liegt eher dran, dass du es dann in nen std string steckst.
Handelt es sich um ne reine Textdatei?

Dir ist fopen und aehnliches lieber? Ist fstream nicht aehnlich? :P
Naja ich finds bequehmer, abef ist nur meine Meinung ;O
11/05/2010 18:29 Shadow992#3
Quote:
Originally Posted by MrSm!th View Post
1. Nur die File Funktionen sehen 0 als Ende
Loesung: Stell den Mode auf Binary/nutze nicht die formatierenden Funktionen, sondern die, die einfach die Daten schreiben, ohne sie als Text zu interpretieren und formatieren oder nimm WinApi


Die Socket Funktionen beachten Nullen eh nicht.
Ich wuerde sagen, es liegt eher dran, dass du es dann in nen std string steckst.
Handelt es sich um ne reine Textdatei?

Dir ist fopen und aehnliches lieber? Ist fstream nicht aehnlich? :P
Naja ich finds bequehmer, abef ist nur meine Meinung ;O
Es können allerlei Programme sein, Bilder, Executeables usw.
Momentan habe ich mich auf Bilder vom Typen bmp beschränkt.
Um die Schnelligkeit des Datenverkehrs zu erhöhen, lasse ich die Dateien zuvor mit zlib comprimieren. Das comprimieren und decomprimieren klappt einwandfrei, das Auslesen jetzt auch.

fstream ist mir etwas ungewohnt, ich benutze auch lieber printf als cout. ;)

Ich habe es jetzt mal versucht ohne std:string, aber jetzt kommt leider noch weniger an, habe ich vielleicht einen Denkfehler?

PHP Code:
void Get_Pic()
{
    
SOCKET sSocket;
    
SOCKET connectedSocket;
    
int res ;
    
FILE pFile;
    
long lSize;
    
char buffer;
    
std::string buf;
    
size_t result;
    
SOCKADDR_IN service;
    
sSocket socketAF_INETSOCK_STREAM);
    
    
buffer = (char*) malloc (sizeof(char)*100001);
    
memset(&service,0,sizeof(SOCKADDR_IN));
    
service.sin_family AF_INET;
    
service.sin_port htons12749 );
    
service.sin_addr.s_addr ADDR_ANY;

    
long rc=bind(sSocket,(SOCKADDR*)&service,sizeof(SOCKADDR_IN));
    
rc=listen(sSocket,10);
    
connectedSocket=accept(sSocket,NULL,NULL);
    while (
1)
    {
        
pFile =fopen("C:\\piccom.bmp""w+" );
        
fputs("",pFile);
        
fclose (pFile);
        while (
strcmp (buffer,"[Ende]" ) != && res>0)
        {
            
res recvconnectedSocketbuffer1000000);
            if (
strcmp (buffer,"[Ende]" ) == 0) break;
            else
            {
                
printf("%s",buffer);
                
pFile fopen ("C:\\piccom.bmp""a+" );
                for (
long i=0;i<sizeof(buffer);i++)
                    
fputc buffer[i] , pFile );
                
fclose (pFile);
                
strcpy(buffer,"");
            }
        }

    }

    
delete [] buffer;

11/05/2010 23:13 MrSm!th#4
Quote:
printf("%s",buffer);
Du wirst wohl kaum in nem Bild einen String finden, also warum printf mit %s? o.ô
Natürlich sucht das nach ner Null und interepretiert sie als Ende.

Zumindest die Ausgabe müsstest du anders schreiben.
Aber ich bin mir sicher, ich verstehe da etwas falsch, denn warum solltest du die Daten eines Bildes als String ausgeben.
Du sagtest doch, du willst ein Bild versenden oder nicht?

Warum behandelst du dann die empfangenen Daten wie einen String?

Nebenbei finde ich die Schleife nicht besonders schön.
Ungeachtet der funktionellen Richtigkeit:

Code:
res = recv( connectedSocket, buffer, 100000, 0);
if(strcmp (buffer,"[Ende]" ) != 0 && res>0)
{
        do
        {
                printf("%s",buffer);
                pFile = fopen ("C:\\piccom.bmp", "a+" );
                for (long i=0;i<sizeof(buffer);i++)
                    fputc ( buffer[i] , pFile );
                fclose (pFile);
                strcpy(buffer,"");
                res = recv( connectedSocket, buffer, 100000, 0);
        } while (strcmp (buffer,"[Ende]" ) != 0 && res>0);
}
Wäre schöner.

Ja, ich weiß, ich bin Perfektionist :p
11/06/2010 04:28 wurstbrot123#5
Code:
ifstream file;
file.open( pathtofile, ios_base::binary );
if(!file.is_open())
	// .....

file.seekg (0, ios::end);
int filesize = file.tellg();
file.seekg (0, ios::beg);

char *filebuffer = new char[filesize+1];
file.read( filebuffer, filesize );
file.close();
Hab mir jetzt nicht alles durchgelesen,
aber so sollte es klappen. Beim send aufruf dann halt
filesize als size parameter angeben.
11/06/2010 10:20 Shadow992#6
Quote:
Originally Posted by MrSm!th View Post
Du wirst wohl kaum in nem Bild einen String finden, also warum printf mit %s? o.ô
Natürlich sucht das nach ner Null und interepretiert sie als Ende.
Ok, das hatte ich mal wieder vergessen.
Quote:
Originally Posted by MrSm!th View Post
Zumindest die Ausgabe müsstest du anders schreiben.
Aber ich bin mir sicher, ich verstehe da etwas falsch, denn warum solltest du die Daten eines Bildes als String ausgeben.
Du sagtest doch, du willst ein Bild versenden oder nicht?

Warum behandelst du dann die empfangenen Daten wie einen String?
Ich lasse den String nur ausgeben, damit ich anschließend sehen kann ob und wieviel erfolgreich ankam. Es ist also mehr ein Test und wird dauerhaft nicht drinnen bleiben. ;)
Quote:
Originally Posted by MrSm!th View Post
Nebenbei finde ich die Schleife nicht besonders schön.
Ungeachtet der funktionellen Richtigkeit:

Code:
res = recv( connectedSocket, buffer, 100000, 0);
if(strcmp (buffer,"[Ende]" ) != 0 && res>0)
{
        do
        {
                printf("%s",buffer);
                pFile = fopen ("C:\\piccom.bmp", "a+" );
                for (long i=0;i<sizeof(buffer);i++)
                    fputc ( buffer[i] , pFile );
                fclose (pFile);
                strcpy(buffer,"");
                res = recv( connectedSocket, buffer, 100000, 0);
        } while (strcmp (buffer,"[Ende]" ) != 0 && res>0);
}
Wäre schöner.

Ja, ich weiß, ich bin Perfektionist :p
Ja, dass du ein Perfektionist bist, ist mir schon oft aufgefallen, aber dafür funktioniert bei dir auch meistens alles. ;)
11/06/2010 12:42 MrSm!th#7
Wenn du die Daten des Bildes ausgeben willst, um zu sehen, wie viele Bytes erfolgreich versendet wurden, musst du die Bytes in einen String konvertieren.
Sonst wird ja die erste Null im Bild als Null-Terminator interpretiert und du bekommst nur die Hälfte ausgegeben ;O

%X als (wie nennt man die Teile nochmal? o.ô) im sprintf format Parameter und das Byte/Dword wird in den dazugehörigen String konvertiert.
Soweit ich weiß, gibt es keinen für ein ganzes Byte Array, also müsstest du mit einer Schleife jedes Byte in den entsprechenden String konvertieren, sie aneinanderketten und das Ergebnis ausgeben ;)


Quote:
Ja, dass du ein Perfektionist bist, ist mir schon oft aufgefallen, aber dafür funktioniert bei dir auch meistens alles.
Schön wärs, nach jedem erstellten Programm folgen 3 Tage nonstop Hardcore Debugging :p
(ok, danach funktionierts dann, also hast du evtl doch Recht, welcher nicht perfektionistische Mensch tut sich sowas nach jedem Programm an, nur um jeden noch so kleinen Fehler zu eliminieren :D)


Kleine Frage an wurstbrot
Quote:
char *filebuffer = new char[filesize+1];
file.read( filebuffer, filesize );
file.close();
new char[filesize+1]

So habe ich das bisher auch immer gemacht, aber mir ist gerade in den Sinn gekommen:
Man nutzt in diesem Falle ja das Char Array als Byte Array und nicht als String, schließlich würde es keinen Sinn machen, eine binäre Datei wie ein Bild als String zu interpretieren.
Ist dann das zusätzliche Byte für den Null-Terminator noch nötig? o.ô Eigentlich doch nicht oder doch?

Hat man ja wieder ein Byte gespart :D