Winsock - Dateien aufteilen und versenden
-
Hallo,
ich versuche bereits seit einiger Zeit, eine Art FTP-Server zu programmieren
-doch ich weis leider net, wie ich die zu versendenen Dateien am besten
mit der "Stück-für-Stück" Methode versenden kann.
Kennt ihr da vielleicht ein passendes Tutorial oder ein paar Codeschnipsel?Vielen Dank!
-
Stell deine Frage vernünftig.
-
Ok Ok..

Ich meine die Methode, wo die zu versendene Datei in Stücken
(zum Beispiel *512 Bytes) gelesen und zum Server gesendet wird.Habe bereits folgenden Ansatz zum Lesen der Datei (könnt ihr mir kurz nen feedback geben, ob ich das problemlos verwenden kann?):
HANDLE hFile = CreateFile("C:\\test.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("Datei konnte nicht geöffnet werden!\n"); return 0; } DWORD dwBytesTotalRead = 0; DWORD dwBytesRead = 0; DWORD dwFileSize = GetFileSize(hFile, NULL); char *cBuf = new char[512 + 1]; while (dwBytesTotalRead < dwFileSize) { if (dwFileSize-dwBytesTotalRead >= 512) { ReadFile(hFile, cBuf, 512, &dwBytesRead, 0); cBuf[512] = '\0'; dwBytesTotalRead = dwBytesTotalRead + dwBytesRead; //cBuf senden } else { ReadFile(hFile, cBuf, (dwFileSize-dwBytesTotalRead), &dwBytesRead, 0); cBuf[dwFileSize-dwBytesTotalRead] = '\0'; dwBytesTotalRead = dwBytesTotalRead + dwBytesRead; //cBuf senden } if(dwBytesTotalRead == dwFileSize) {MessageBox(0,0,0,0);} } CloseHandle(hFile); delete[] cBuf;
-
Ach Mensch...
ich will doch nur ein Feedback, ob ich den Code im letzen Posting für das Lesen
einer Datei verwenden kann
- funktioniert das zum Beispiel auch bei Dateien
im Binary - Format oder können mitReadFile(...)nur Dateien im Ascii-Format gelesen werden?
Freue mich über jede Antwort

Um's nochmal zu verdeutlichen: Ich möchte mithilfe von Sockets und einer
TCP-Verbindung eine Datei von einem Clienten zu einem Server übertragen.
Da die Datei aber mehr als 3MB groß sein wird, kann ich nicht einfach die
komplette Datei mit send(...) senden und auf dem Server empfangen (das würde 1.
zu lange dauern und man möchte 2. ja auch mal wissen, wie lange der Transfer
wohl noch dauert und wieviele Bytes bisher gesendet wurden.)Darum hab ich mir mal überlegt, die Datei in einzelnen "Paketen"
(zum Beispiel *512 Bytes) zu versenden. Erst, wenn eine Empfangsbestätigung
der 512 Bytes vom Server beim Clienten angekommen ist, werden die nächsten
512 Bytes gesendet und so weiter..Der Code im vorigen Posting soll die entsprechende Datei Stück für Stück
einlesen. Da, wo ich die Kommentare eingefügt habe, wird geprüft, ob bereits
eine Empfangsbestätigung der letzten 512 Bytes vom Server vorhanden ist.
Wenn ja, werden die nächsten 512 Bytes in der Dateieingelesen, versendet
und so weiter..Doch ich weis leider nicht, ob das auch problemlos mit Dateien im Binary-Format
funktioniert (bei der Ausgabe des Buffers mit printf(...) ist mir das Programm
bei einer Videodatei abgestürzt
).
-
Pedda schrieb:
Um's nochmal zu verdeutlichen: Ich möchte mithilfe von Sockets und einer
TCP-Verbindung eine Datei von einem Clienten zu einem Server übertragen.
Da die Datei aber mehr als 3MB groß sein wird, kann ich nicht einfach die
komplette Datei mit send(...) senden und auf dem Server empfangen (das würde 1.
zu lange dauern und man möchte 2. ja auch mal wissen, wie lange der Transfer
wohl noch dauert und wieviele Bytes bisher gesendet wurden.)Darum hab ich mir mal überlegt, die Datei in einzelnen "Paketen"
(zum Beispiel *512 Bytes) zu versenden. Erst, wenn eine Empfangsbestätigung
der 512 Bytes vom Server beim Clienten angekommen ist, werden die nächsten
512 Bytes gesendet und so weiter..tcp ist aus benutzersicht ein datenstrom. man braucht nichts in pakete zu zerstückeln und keine selbstgemachten 'ack's. du kannst einfach daten mit readfile() in einen puffer holen und dann alles was ankam mit send() abschicken (einfacher puffer-transfer vom readfile fifo in den socket-fifo). die grösse des puffers spielt dabei fast keine rolle (anzahl der schleifendurchläufe kann man vernachlässigen). kann 100 bytes oder 100kb sein, ist egal. tcp und readfile regeln alles selber.
äääh... wenn du unbedingt pakete mit bestätigung machen willst, dann nimm udp. aber solche synchronen ping-pong protokolle sind echt lahm.
btw: noch besser ist natürlich das: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/transmitfile_2.asp
-
Der Code ist irgendwie verwirrend. Versuch den mal neu zu schreiben. Man kann das auf jeden Fall so schreiben das man nur an einer Stelle ReadFile aufrufen muss. Und cBuf musst du doch nicht dynamisch anlegen. Das hat keinen Sinn, wenn du dann die Größe fest codierst.
-
net schrieb:
tcp ist aus benutzersicht ein datenstrom. man braucht nichts in pakete zu zerstückeln und keine selbstgemachten 'ack's. du kannst einfach daten mit readfile() in einen puffer holen und dann alles was ankam mit send() abschicken (einfacher puffer-transfer vom readfile fifo in den socket-fifo). die grösse des puffers spielt dabei fast keine rolle (anzahl der schleifendurchläufe kann man vernachlässigen). kann 100 bytes oder 100kb sein, ist egal. tcp und readfile regeln alles selber.
äääh... wenn du unbedingt pakete mit bestätigung machen willst, dann nimm udp. aber solche synchronen ping-pong protokolle sind echt lahm.
btw: noch besser ist natürlich das: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/transmitfile_2.aspVerstehe ich leider nicht so ganz - ich könnte also praktisch per ReadFile die
komplette Datei einlesen und den x byte großen Buffer mit send(...) versenden?Wie sieht'n das denn dann beim Server aus - wie komme ich denn da dann an die
Anzahl der empfangenen Bytes und an die Restdauer des Dateitransfers
(mein Ziel ist es ja, eine beliebig große datei zu übertragen; auf dem Server
soll aber zwischendurch angezeigt werden, wie viele Bytes schon insgesamt
übertragen wurden)?TransmitFile() könnte ich natürlich auch verwenden, doch ich finde in der msdn
irgendwie keine Informationen dazu, wie ich die Datei empfangen kann
-
Pedda schrieb:
Verstehe ich leider nicht so ganz - ich könnte also praktisch per ReadFile die
komplette Datei einlesen und den x byte großen Buffer mit send(...) versenden?sinngemäss ungefähr so...
... char buffer[0x4000]; ... while (ReadFile (...., buffer, sizeof(buffer), &bytes_read, ....)) { // fertig? if (bytes_read == 0) break; // senden... while (bytes_read) { int bytes_sent = send (socket, buffer, bytes_read, ....); if (bytes_sent == SOCKET_ERROR) { // fehler beim senden, verbindung weg usw. ... } // falls socket input buffer voll nochmal den rest senden bytes_read -= bytes_sent; } } ...Pedda schrieb:
Wie sieht'n das denn dann beim Server aus - wie komme ich denn da dann an die
Anzahl der empfangenen Bytes und an die Restdauer des Dateitransfersder weiss leider nicht wieviele daten kommen. musste ihm mitteilen z.b. indem du diese information zuerst sendest
Pedda schrieb:
(mein Ziel ist es ja, eine beliebig große datei zu übertragen; auf dem Server
soll aber zwischendurch angezeigt werden, wie viele Bytes schon insgesamt
übertragen wurden)?siehe oben. der code ist zwar nicht lauffähig aber zeigt ungefähr wie's gehen kann
Pedda schrieb:
TransmitFile() könnte ich natürlich auch verwenden, doch ich finde in der msdn
irgendwie keine Informationen dazu, wie ich die Datei empfangen kann
recv(), WSARecv(), was du willst.
-
Hey net!
Vielen Dank für deine Antworten!
Habe in nem französischen Programmiererforum genau das zu TransmitFile gefunden,
was ich suchte ...:/************************************ * Programme principal : main * - Client ************************************/ int main(int argc, char **argv[]) { SOCKET sock; struct sockaddr_in sin; int ret; char buffer[1024]; char espace[] = " "; char *name = "envois.txt"; /* Initialise Winsock */ InitWinsock(); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); /* Appel de la fonction socket */ if (sock != INVALID_SOCKET) /* Controle d'erreurs */ fprintf(stdout, "[*] Socket cree avec succes.\n"); else { fprintf(stderr,"Erreur lors de la creation du socket, Code d'erreur : %d\n",WSAGetLastError()); return (-1); } memset(&sin, 0, sizeof(struct sockaddr_in)); cout << "IP server : "; cin.getline(buffer,100); sin.sin_addr.s_addr = inet_addr(buffer); /* inet_addr(ip_du_serveur); */ sin.sin_family = AF_INET; sin.sin_port = htons(4148); /* htons(port_du_serveur); */ connect(sock, (SOCKADDR *) & sin, sizeof(struct sockaddr_in)); /* Connexion */ if (sock != SOCKET_ERROR) /* Controle d'erreurs */ fprintf(stdout, "[*] Connexion effectuee avec succes.\n"); else { fprintf(stderr,"Erreur lors de la connection, Code d'erreur : %d\n",WSAGetLastError()); return (-1); } HANDLE hFile = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( (hFile == 0) || (hFile == INVALID_HANDLE_VALUE) ) cout << "Error " << hFile << "\n"; else cout << "Success " << hFile << "\n"; long size = GetFileSize(hFile, NULL); long total = 0; long n = 0; long taille = 1024; ifstream entree(name, ios::binary); memset(buffer, 0, 1024 * sizeof(char)); *((long*)&buffer) = size; send(sock,buffer,sizeof(long),0); memset(buffer, 0, 1024 * sizeof(char)); send(sock,name,sizeof(buffer),0); cout << name << endl; ret = recv(sock, buffer, 2, 0); char flag[2]; sprintf(flag,"%s", "ok"); if(flag != buffer) { if (! (TransmitFile(sock,hFile,size,0,NULL,NULL,TF_DISCONNECT | TF_REUSE_SOCKET))) cout << "Erreur Send_file TransmitFile : " << WSAGetLastError() << endl; else { cout << "Envois ok" << endl; } } closesocket(sock); /* Ferme le socket */ system("PAUSE"); return (0); }/************************************ * Traitement des transferts * - Server ************************************/ void traite_connexion(SOCKET socket_client) { int ret; char buffer[17520]; char *buff = NULL; long total; buff = (char *) malloc(256 * sizeof(char *)); ret=recv(socket_client,buff,sizeof(buff),0); buff[ret]='\0'; total = *((long*)buff); long size = total; memset(buffer, 0, 17520 * sizeof(char)); ret=recv(socket_client,buffer,sizeof(buffer),0); char *name = buffer; cout << name << buffer; ofstream fichier( name, ios::binary); memset(buffer, 0, 17520 * sizeof(char)); char flag[2]; sprintf(flag,"%s", "ok"); cout << flag << endl; ret = send(socket_client, flag, sizeof(flag), 0); int i = 0; while(total>17520) { ret = recv(socket_client,buffer, 17520, 0); fichier.write(buffer,ret); i++; cout << "Ecriture fichier... " << i << " Retour... " << ret << endl; total -= ret; } recv(socket_client, buffer, total, 0); fichier.write(buffer, total); cout << "Ecriture fin de fichier..." << total << endl; fichier.close(); closesocket(socket_client); }(http://www.developpez.net/forums/viewtopic.php?t=291970)
Werde aber wahrscheinlich erst die Informationen der Datei (Grösse, Name, etc.)
zum Server senden, kurz eine Antwort abwarten und die Datei dann übertragen.
(siehe while-Schleife).Nun hätte' ich aber da noch ne Frage:
Wenn ich die Teile der Datei alle mit recv(...) in einer while Schleife
empfange, könnte es doch passieren, dass sich die Daten noch in dem übertragenen
Socket-Stream befinden und erneut in die Datei geschrieben werden, oder werden
die automatisch nach dem Empfang gelöscht?(Beispiel: Client -> -> Empfang -> Server)
Nochmals vielen Dank!

-
Pedda schrieb:
Wenn ich die Teile der Datei alle mit recv(...) in einer while Schleife
empfange, könnte es doch passieren, dass sich die Daten noch in dem übertragenen
Socket-Stream befinden und erneut in die Datei geschrieben werden, oder werden
die automatisch nach dem Empfang gelöscht?der empfangspuffer eines sockets wird von der einen seite vom protokollstack gefüllt und auf der anderen seite holt sich die anwendung die daten raus. alles was (z.b. mit recv()) aus dem puffer geholt wurde ist da nicht mehr drin. wenn nichts mehr drin ist, gibt recv() 0 zurück. wenn man recv() lange nicht aufruft, wird die verbindung angehalten d.h. die gegenstelle sendet auch nicht mehr, bis wieder platz im puffer ist.
-
Ok - dann bedanke ich mich hiermit nochmal vielmals für alle Antworten

Achso: Es ist doch richtig, dass man für die Benutzung der Winsock2 - Funktionen
nur die ws2_32.lib und die Mswsock.lib linken muss; die dazu gehörigen
Header-Dateien werden doch schon in der windows.h eingebunden, oder nicht?(Wenn ich versuche, die mswsock.h zu inkludieren, wird mir mitgeteilt, dass
_TRANSMIT_FILE_BUFFER (oder so) schon definiert wurde - wenn ich die rauslasse,
windows.h inkludiere und ws2_32.lib und Mswsock.lib linke, funktioniert allet
prima:)thx!
-Pedda
PS: Klasse Forum
