C++ Puffergröße Dateiserver

Cypog

Newbie
Registriert
Mai 2009
Beiträge
7
Tag zusammen,

ich programmiere gerade einen TCP Datei-Server und -Klienten.
Das Prinzip funktioniert ganz einfach:

Klient stellt Verbindung her
Server sendet Eintrag (Dateiname + Größe)
Klient vergleicht Dateigröße
Klient fordert Datei an, falls Dateigrößen unterschiedlich

Das Senden der Datei funktioniert so:
Klient fordert Paket an (bis jetzt 512 Byte)
Server sendet Paket

klappt alles wunderbar, so lange die Dateien nicht groß sind. (<100KB)

Nur leider habe ich auch vor größere Dateien (damit meine ich max. 3MB)
zu versenden.
Wenn ich weiterhin dieses Prinzip verwende, würde es ewig dauern eine Datei runterzuladen.
Beispiel 80KB:
160 * 512 = 160 Anfragen
1 Anfrage: 50ms
=8000ms
Somit würde ich schon für eine 80kB Datei 8 Sekunden nur fürs Anfordern des nächsten Paketes verbraten.
Ich hab übrigens 512 Byte gewählt, weil ich auf http://www.win-tux.de/c_028_007.htm#RxxobKap02800704002D231F022193 gelesen hatte, dass 512 Byte (richtig, ich hab mich verlesen ;), es sollen KB sein) die richtige Puffergröße wäre.

Hab es dann auf 512KB vergrößert, was zur Folge hat, dass das Programm während dem Übertragen unregelmäßig die Verbindung abbricht.
Das macht es immer, wenn ich eine Größe über 1024 Byte wähle.

Damit hab ich 2 Fragen:
1. Was ist die optimale Puffergröße?
2. Welches Prinzip sollte ich beim Senden der Datei verwenden?

Danke fürs lesen, hoffe ihr könnt mir bei dem Problem helfen
 
160 * 512 = 160 Anfragen

Mit der Rechnung komm ich nich klar :P

Äh wieso schickt der Server die Datei nicht einfach in einem Stück komplett rüber?
Das ist im übrigen nicht normal, dass bei Puffern >1kb die Verbindung abbricht. Du solltest dir deinen Code nochmal ansehen oder zumindest ausschnitte hier posten.
 
Das mit der Puffergröße könnte dann kommen, wenn du DF gesetzt hast und der IP-Frame größer als die MTU wird.

Davon mal abgesehen - du erwähnst Pakete. Du hast dir also eine Paketimplementierung geschrieben? Oder gehst du davon aus, dass ein send/recv ein "Paket" verschickt/empfängt? Letzteres wäre ein Trugschluss - TCP ist streambasiert. Es liegt an dir selbst, einen Paket-Layer dadraufzulegen, falls du das wirklich willst.
 
@dEad0r: Sollte eher ein Vergleich als eine Rechnung sein ;)
80 * 1024 / 512 = 160

@7H3 N4C3R: Mit Paket mein ich einfach nur einen Datenblock, in dem Fall 512 Byte der Datei.

Hier mal der Ausschnit, der fürs Empfangen der Datei zuständig ist:

Code:
int LoadMap(const char * saveto, const char * mapname, long filesize)
{
	//char saveto[MAX_PATH_LEN] = "";
	//memcpy(saveto, sapath, MAX_PATH_LEN);
	//strncat(saveto, mapname, MAX_PATH_LEN);
	FILE *datei = fopen(saveto, "wb");

	if (datei == NULL)
		cout << "Kann Datei " << saveto << " nicht speichern.\n";
	else
	{
		char msg[128] = "file ";
		strncat(msg, (const char*)mapname + 1, sizeof(msg));
		if (send(sock, msg, strlen(msg) + 1, 0) == -1)
			cout << "Konnte Initialisierung von Dateitransfer nicht senden: " << WSAGetLastError() << '\n';
		else
			cout << "Beginne Dateitransfer von Datei " << mapname << ".\n";
		int rstate = 0; char rdata[BUF_LEN] = "";

		while (!sshutdown)
		{
			if ((rstate = recv(sock, (char*)&rdata, sizeof(rdata), 0)) == -1)
			{
				cout << "Fehler beim Erhalten von Daten: " << WSAGetLastError() << '\n';
				break;
			}
			if (rstate == 0)
			{
				cout << "Der Server hat die Verbindung während dem Laden beendet.\n";
				break;
			}
			fwrite(rdata, 1, rstate, datei);
			send(sock, "#\0", 2, 0);
			filesize -= rstate;
			//cout << filesize << '\n';
			if (filesize == 0)
			{
				//cout << rdata << '\n';
				cout << "Datei erfolgreich geladen.\n";
				//cout << rstate << '\n';
				break;
			}
			else if (rstate != sizeof(rdata))
			{
				cout << rstate << ' ' << sizeof(rdata) << '\n';
				cout << "Fehler: unerwartetes Dateiende.\n";
				break;
			}
			//send(sock, "#\0", 2, 0);
		}
		fclose(datei);
		//send(sock, "#\0", 2, 0);
	}
	return 0;
}
 
Empfängst du vorher schon was vom Server auf der selben Verbindung? Der Code dazu wäre interessant.
 
Ja, wenn der Klient die Einträge anfordert:

Code:
bool GetMapData()
{
	int rstate = 0; char rdata[BUF_LEN] = "";

	//memcpy(rdata, "req", 3);
	//rdata = "req";
	//send(sock, rdata, 1, 3);
	if (send(sock, "req", 3, 0) != -1)
		cout << "Fordere Versionsinfo an.\n";
	else
		cout << "Kann Versionsinfo nicht anfordern: " << WSAGetLastError() << '\n';

	while (!sshutdown)
	{
		if ((rstate = recv(sock, (char*)&rdata, sizeof(rdata), 0)) == -1)
		{
			cout << "Fehler beim Erhalten von Daten: " << WSAGetLastError() << '\n';
			return false;
		}
		if (rstate == 0)
		{
			cout << "Der Server hat die Verbindung beendet.\n";
			return true;
		}
		rdata[rstate] = 0;
		if (server_cmd(rdata) == 0)
		{
			cout << "Antwort (" << rdata << ") unbekannt, beende Verbindung\n";
			//cout << rstate << '\n';
			closesocket(sock);
			return false;
		}
	}
	return true;
}
 
Da wäre jetzt mal interessant, wie die beiden miteinander kommunizieren.

Sendet der Server direkt nach diesen Versionsinfos den Inhalt? Dann wirst du mit dem recv in GetMapData() vermutlich einen Teil der Daten überlesen, wenn du den restlichen Buffer-Inhalt nicht sicherst.
 
Ne, natürlich wartet der Server auf eine Antwort:

Der Server sendet nach dem "req" einen Eintrag "map Dateiname Dateigröße"
Danach vergleicht der Klient die gesendete Dateigröße mit der Größe der lokalen Datei.
Ist diese unterschiedlich oder die Datei nicht vorhanden, sendet der Klient eine Anfrage:
"file Dateiname"
Der Dateitransfer beginnt dann.

Alle Nachrichten außer der Dateitransfer werden in dieser Funktion bearbeitet:
Code:
int server_cmd(const char * cmd)
{
	if (strncmp(cmd, "/msg ", 5) == 0)
	{
		cout << "Nachricht:\n";
		cout << (cmd + 5) << '\n';
		return 1;
	}
	if (strncmp(cmd, "map", 3) == 0)
	{
		char mappath[MAX_PATH_LEN] = "";
		char complpath[MAX_PATH_LEN] = "";
		memcpy(complpath, sapath, MAX_PATH_LEN);
		char fsize[20] = "";
		getstrspc2(cmd, 1, "  ", mappath, sizeof(mappath));
		cout << "Dateiinformationen erhalten: " << mappath << '\n';
		//cout << cmd << '\n';
		strncat(complpath, mappath, MAX_PATH_LEN);
		getstrspc2(cmd, 2, " \0", fsize, sizeof(fsize));
		if (fsize[0] == 0)
			send(sock, "/msg Fehler: Dateigrӧe invalid.\0", 33, 0);
		else
		{
			bool bsend = false;
			long lsize_new = atol(fsize);
			long lsize = 0;
			FILE * datei = fopen(complpath, "rb");
			if (datei == NULL)
			{
				//cout << "Datei " << complpath << "existiert nicht.\n";
				char fpath[MAX_PATH_LEN] = "";
				getpath(complpath, fpath, MAX_PATH_LEN);
				if (_access(fpath, 0) != 0)
				{
					cout << "Pfad existiert nicht.\n";
					return false;
				}
				else
					LoadMap(complpath, mappath, lsize_new);	
			}
			else
			{
				fseek(datei, 0, SEEK_END);
				lsize = ftell(datei);				
				fclose(datei);
				cout << "Vergleiche DateigrӇen: " << lsize << " " << lsize_new << '\n';
				if (lsize != lsize_new)
				{
					LoadMap(complpath, mappath, lsize_new);
				}
				else
				{
					cout << "Datei ist auf dem neustem Stand, fordere n„chsten Eintrag an.\n";
					if (send(sock, "/next\0", 6, 0) == -1)
						cout << "Fehler: Konnte Antwort nicht senden.\n";
				}
			}
		}
		return 1;
	}
	return 0;
}
 
Zuletzt bearbeitet:
Zurück
Oben