C HTTP-Server -->> Dateien an Client/Browser senden und anzeigen lassen...

dragonabllz

Ensign
Registriert
Mai 2011
Beiträge
254
Hallo Leute,

ich hoffe ich bin hier im richtigen Forum.
Kurz zu mir: Ich bin Programmier-Einsteiger, aber kenne mich gut in den Grundlagen von C aus.
Momentan beschäftige ich mich mit Servern in C unter Linux.

Folgendes: Wir haben inzwischen ein primitiven HTTP-Server* programmiert, der eigentlich kaum was kann, außer Verbindungen annehmen und so weiter...
Wir wollen jetzt, dass der Server, Dateien auf Anfrage an einen Browser sendet.
Also, wenn ein User z.B. GET Bild.jpg oder sowas angibt, muss das Bild in dem jeweiligen Ordner auch gefunden und ausgegeben werden.
Es existiert im Prinzip nur ein Ordner namens "htdocs" der die Dateien beinhalten soll.
Jetzt kommen wir zum eigentlichen:
Wie macht man das? Also das Parsen können wir soweit (also Dateiname und Methode GET und so weiter auslesen), aber wie schicke ich nun eine Datei an einem Browser (z.B. Firefox), der mit unserem Server kommuniziert? Wie geht sowas in C? Vor Allem, es können ja beliebige Dateien sein, ob nun Textdatei, Bilder oder Videos. Macht man sowas mit HTML-Code oder so?


* Wir arbeiten an einem PC, sprich wenn wir mit dem Server kommunizieren, nutzen wir im Browser "localhost". Weil wir sind noch am Anfang und wollen uns nur in die Grundlagen und den Aufbau von Servern und so einarbeiten.


Ich hoffe die Frage klingt nicht dumm, bin neu in diesem Gebiet


PS:

So sieht übrigens der Server aus, falls das hilft (Code ist in der PDF Datei):

http://www.file-upload.net/download-7535588/Server.pdf.html

Die Methoden zum Parsen sind aber noch nicht drin. Das ist jetzt nur unser primitiver Server
 
HTTP-Protokoll Dokumentation. Ich weiß aber grad nicht wo eine gute ist. Ich hätte mir zum Test ne Website mit z.B. nur einem Bild gemacht und die recv() Funktion in einem Browser gehookt, sodass sie mir anzeigt was empfangen wird. Ein Bild wird deshalb meines wissens nach wie die Seite gesendet, nur halt mit nem speziellen tag und dem link zu dem bild. Der Browser erkennt dann, dass diese Links identisch sind und kann dort das Empfangene Bild einfügen.

LG Tigerass
 
Also ich denke, das macht jeder Server gleich:
Zuerst mal gucken, ob's die Datei gibt, Zugriffsrechte und so prüfen.
Dann sendest du ganz normale HTTP-Header, halt nicht mit Content-Type: text sonder mit image/jpg oder so.

Und dann sendest du einfach dein Bild, indem du die Datei öffnest, sie ausliest und an deinen Socket sendest.
(Tipp: Nicht das ganze Bild auf einmal lesen, es könnte ja mal ne 20 GB Datei sein)
 
hi, also erstmal danke für die Antworten.
Aber ich komme nicht ganz weiter. Ich verstehe immer noch nicht ganz wie die z.b. die Grafik angezeigt werden soll im Browser.
Ich habe es so gemacht:
1. Eine Datei geöfnet mit fopen("test.jpg","rb")
2. die Datei ausgelesen mit fread und in einem Char Array testbuffer gesteckt.
3. Header erstellt und testbuffer direkt hinterher mitgegeben, also als Body. (natürlich habe ich /r/n nicht vrgessen).

Aber es klappt nicht. Wenn ich dann per localhost auf den Server zugreife, wird die Meldung angezeigt: "Die Grafik "http://localhost:31337/" kann nicht angezeigt werden, weil sie Fehler enthält."
Anmerkung: 31337 ist die von mir vergebene Portnummer.

Wieso klappt das nicht? Ich werde gleich versuchen den gesmten Code heir hochzuladen...
Ergänzung ()

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 31337
#define BUFFER_SIZE 100024

int sockfd;
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);

FILE *pFile;
char *cfile;
int filelen;






/**
 * Fehlerbehandlung.
 */
void error(char *msg) {
	fprintf(stderr, "%s\n", msg);
	exit(1);
}


/**
 * Erstellt und Konfiguriert den Netzwerk-Socket, Ÿber den die Verbindungen
 * angenommen werden.
 */
void setup_socket() {
	/*
	 * Setzt Konfigurationsvariablen fŸr den Socket, z.B. die Portnummer.
	 */
	bzero((char *) &serv_addr, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(PORT);

	/*
	 * Erstelle den Socket.
	 */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
		error("ERROR opening socket");

	/*
	 * Melde, dass der Socket eingehende Verbindungen akzeptieren soll.
	 */
	if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
		error("ERROR on binding");

	/*
	 * Horche auf dem Socket nach eingehenden Verbindungen. Es werden maximal
	 * fŸnf gleichzeitige Verbindungen erlaubt.
	 */
	listen(sockfd, 5);
}


/**
 * Die Hauptschleife, in der eingehende Verbindungen angenommen werden.
 */
void main_loop() {

	int newsockfd;
	int length;
	char buffer[BUFFER_SIZE];

	/*
	 * Die Hauptschleife des Programms.
	 */
	while (1) {

		/*
		 * Der accept()-Aufruf blockiert, bis eine neue Verbindung rein kommt.
		 */
		newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
		if (newsockfd < 0)
			error("ERROR on accept");

		/*
		 * Lies die ankommenden Daten von dem Socket in das Array buffer.
		 */
		bzero(buffer, sizeof(buffer));
		length = read(newsockfd, buffer, sizeof(buffer) - 1);
		if (length < 0)
			error("ERROR reading from socket");


		sprintf(buffer, "%s\r\n%s\r\n%s\r\n%s\r\n%s%d\r\n\r\n%s",
				"HTTP/1.1 200 OK", "Location: http://www.trololol.de/",
				"Content-Type: image/jpeg", "Server: ein server",
				"Content-Length: ", filelen+1, cfile);
		length = strlen(buffer);
		/*
		 * Schreibe die ausgehenden Daten auf den Socket.
		 */
		length = write(newsockfd, buffer, length);
		if (length < 0)
			error("ERROR writing to socket");

		/*
		 * Gib die eingegangenen Daten auf der Kommandozeile aus.
		 */
		printf("%s", buffer);

		/*
		 * Schlie§e die Verbindung.
		 */
		close(newsockfd);
	}

	/*
	 * Schlie§e den Socket. Dieser Aufruf sollte wegen der Endlosschleife niemals
	 * ausgefŸhrt werden.
	 */
	close(sockfd);
}

int main(int argc, char *argv[]) {

	pFile = fopen("/home/vbox/Bilder/apfel.jpg", "rb");
	if(!pFile){
		return 0;
	}

	fseek(pFile, 0, SEEK_END);
	filelen = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);

	cfile = (char *)malloc(filelen+ 1);
	if(!cfile){
		fprintf(stderr, "Memory error!");
		fclose(pFile);
		return 0;
	}

	fread(cfile, filelen, 1, pFile);
	fclose(pFile);

	setup_socket();
	main_loop();

	return 0;
}
 
Hi,

ein paar Sachen, die mir aufgefallen sind:

1) Normalerweiße verwendet man send/recv anstatt read/write für Socket-Operationen.
2) Es wird nicht funktionieren, das Bild direkt mit "%s" im Formatstring ausgeben zu lassen. Ich würde zuerst den Header schicken und anschließend erst die Bilddatei. Und dann direkt cfile über den Socket schicken, nicht erst in einen String umwandeln.
3) write() (bzw. send()) müssen nicht unbedingt alle Daten schicken, die du übergibst, v.a. nicht wenn testbuffer sehr groß ist. Überprüf doch mal, welchen Rückgabewert du von write genau bekommst. Wenn dieser ungleich filelen ist, dann musst du write nochmal aufrufen.
 
Zurück
Oben