Netzwerkprogrammierung UDP in C

#1

ich habe folgende Aufgabe:

Implementieren Sie einen Sender (sender_udp), der eine beliebige Datei einliest und Dateiname, Dateigröße, Dateiinhalt sowie den berechneten SHA1-Hashwert via UDP verschickt und auf eine Rückmeldung über den Erfolg der Übertragung wartet. Der Sender soll wie folgt aufgerufen werden:

$./sender_udp <Addresse_des_Empfängers> <Port_des_Empfängers>

Weiterhin sollen Sie einen Empfänger (receiver_udp) implementieren, welcher diese Übertragung annimmt.
Die empfangene Datei wird unter ihrem alten Namen in einem vor Programmstart angelegten Ordner (received) vollständig gespeichert. Eventuell vorhandene Dateien mit gleichem Namen werden überschrieben. Über den Inhalt der empfangenen Datei wird ebenfalls ein SHA-1 Hashwert berechnet. Dieser wird mit dem Übertragenen verglichen und das Resultat an den Sender gemeldtet. Der Empfänger wird wie folgt aufgerufen:

$./receiver_udf <Port_des_Empfängers>

Bei der Übergabe von zu vielen, zu wenigen oder ungültigen Parametern soll jeweils eine entsprechende Fehlermeldung und eine allgemeine Nutzungshilfe ausgegeben werden.
Unter zuhifenahme der bereitgestellten Formatstrings und Methoden (Aufgabe2.h) müssen die folgenden Informationen von Sender und Empfänger ausgegeben werden:

-Dateiname (ohne Pfad)
-Dateigröße
-SHA1- Hashwert
Übertragungsstatus

für diverse Fehler, die während der Ausführung auftreten können, sind die entsprechenden Ausgaben ebenfalls im Header definniert. Beachten Sie bei Ihrer Implementierung weiterhin folgende Hinweise:

-Beide Programme sollen maximal 10 Sekunden auf ein Paket warten, nachdem sie das letzte Paket empfangen oder versendet haben. Bei Überschreitung sollen sich die Programme nach entsprechender Meldung(timeout_error) beenden.
Dies betrifft nicht die Zeit vor dem ersten Paket.

  • Wählen Sie die Paetgröße so, dass die maximale MTU einer PPPoE-Verbindung nicht überschritten wird.

-Sollte ein Fehler auftreten oder ein nicht dem Protokoll enstsprechendes Paket empfangen werden, sollen sich Ihre Programme nach Ausgabe einer Fehlermeldung (packet_error) beenden.

  • Ihr Programm muss nicht in der Lage sein, parallel mehrere Dateien zu verschicken oder zu empfangen. Ebenso muss nichts empfangen werden, wenn das Protokoll es nicht vorsieht. Die Unterstützung von IO- Multiplexing ist somit nciht nötig.

-Die SHA-1-Hashwerte dürfen Sie über die vorhandenen Methden in OpenSSL berechenn. Die entsprechennden Bibliotheken müssen beim Kompilieren gelinkt werden -lssl -lcrypto

Protokollspezifikation

Das für die Übertagung benötigte Protokoll ist wie folgt spezifiziert: Das erste Byte gibt jeweils den Typ des Pakets an und legt somit dessen Aufbau fest. Die Werte für den Identifikator sind im entsprechenden Header definiert. Der eigentliche Nachrichtenaustausch läuft wie folgt ab:

(1) Als erstes wird eine Paket mit dem Typ-Identifikator HEADER_T geschickt, das in dieser Reihenfolge

  • Länge des Dateinamens (ohne Pfad) als unsigned short
    -Dateiname(ohne Pfad) als C String ohne die Null Terminierung
  • Länge der Datei in Byte als unsigned integer
    enthält

(2)

Dann wird der Dateiinhalt in der entsprechend nötigen Anzahl von Paketen mit dem Typ-Indentifikator DATA_T bertagen. Jedem Datenpaket wird hierbei eine bei 0 begindende und jeweils um 1 inkrementierte Sequenznummer als unsigned integer hinzugefügz, die beim Empfänger überprüft werden muss. Empfängt dieser iein Paket in der falschen Reihenfolge, so soll er sich , nach Ausgabe der entsprechenden Meldung(order_error), beenden.

(3)

Nachdem der Inhalt übertragen wurde, folgt der vom Sender errechnete SHA-1 Hashwert in einem Paket mit Typ-Identifikator SHA1_T

(4) Zuletzt überträgt der Empfänger das Ergebnis seines SHA1-Vergleichs im folgenden Format an den Sender:

-Typ-Indentifikator als unsigned char (SHA1_CMP_T)

-SHa1 Vergleichsergebnis: SHA1_CMP_OK/SHA1_CMP_ERROR als char

Mein Sender aktuell:

#include <stdio.h>
#include <string.h>
#include <linux/limits.h>
#include <sys/stat.h>
#include <openssl/sha.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "Aufgabe2.h"


void printManual() {
	
	printf("das Programm sender_udp bitte auf folgende Weise benutzen: 
");
	printf("./sender udp <Addresse_des_Empfängers> <Port_des_Empfängers> <Dateipfad>
");
	
	exit(0);
	
}

char Port[4];

char Dateipfad[PATH_MAX];

struct stat fileStats;

char delimiter[] = "/";

char text[300];


struct sockaddr_in dest;

//Ermittelt den Namen einer Datei aus dem Dateipfad
char * determFileName(char * pfad) {
	
	char * ptr;
	char * ptrprev;
	
	ptr = strtok(pfad,delimiter);
	
	while(ptr != NULL) {
		
	  ptrprev = ptr;
	  
	  ptr = strtok(NULL, delimiter);
	}
	return ptrprev;
}



int create_socket() {
	
	int fd;
	
	fd = socket(AF_INET,SOCK_DGRAM,0);
	
	if(fd < 0) {
		
		printf("Fehler: Socket konnte nicht erstellt werden /n");
	}
	
	return fd;
	
}

void send_my_msg(char * msg) {
	dest.sin_family = AF_INET;
	dest.sin_port = htons(4711);
	dest.sin_addr.s_addr = inet_addr("127.0.0.1");
	
	
	//char msg[64];
	
	//strcpy(msg, "hello World");
	
	int err, fd;
	
	fd = create_socket();
	
	err = sendto(fd, msg, strlen(msg)+1,0,(struct sockaddr *) &dest, sizeof(struct sockaddr_in));
	
	if(err <0) {
		printf("senden fehlgeschlagen");
    	
	}
	
	
	
	
}

void Console_Outprint() {
	
	
	
	
}


void datei_einlesen(char * dateipfad) {
	
	
	FILE *datei;
	
	
	datei = fopen(dateipfad,"r+b");
	
	if(datei == NULL) {
		printf("Datei konnte nicht geöffnet werden!");
	}
	
	else {
		
		stat(Dateipfad,&fileStats);
		
		fscanf(datei,"%100c", text);
		
		text[100] = '\0';
	
	
	
}}


//Programm beenden mit timeout_error

void quitProgram() {
	
	printf(timeout_error);
	
	exit(0);
	
	
	
	

}



void createHeaderPackage() {
	
	char tmp[12];
	
	tmp[0] = HEADER_T;
	
	
	
	
}

//erstellt und verschickt das SHA1 Hash Packet
void createSHA1Package(char *data) {
	
	
	
	size_t length = strlen(data);
	
	unsigned char hash[SHA_DIGEST_LENGTH];
	
	SHA1((unsigned char *)data,length,hash);
  
    static unsigned char  msg[2];
  	
  	msg[0] = SHA1_T;
  	
  	
  	
  	//int i;
  	
  //	for(i = 1; i < 21; i++) {
		
	//	printf("%s 
", hash[i-1]);
		
	//	msg** = hash**;
//	}
	
	printf("%i",msg);
	
	printf("
");
	
	//send_my_msg(msg);
	
	
  	
}

int main(int argc, char ** argv) {
	
	
	if(argc != 4) {
		
		printManual();
		
		
		
	}
	
	createSHA1Package("hallo Welt");
	
	//quitProgram();
	
	//datei_einlesen(argv[3]);
	
	//printf("%s", text);
	
	//strcpy(Dateipfad,argv[3]);
	
	//FILE *datei;
	//char text[300+1];
	
	//datei = fopen(Dateipfad,"r");
	
	//if(datei == NULL) {
	//	printf("Datei konnte nicht geöffnet werden!");
	//}
	
	//else {
		
		//stat(Dateipfad,&fileStats);
		
		//fscanf(datei,"%100c", text);
		
		//text[100] = '\0';
		
		//printf("%s
",text);
		
		//printf("die Größe der Datei lautet %d Bytes 
", (int)fileStats.st_size);
		
		//printf("der Name der Datei lautet %s 
", determFileName(Dateipfad));
		
	    //printf("der SHA1-Hashwert der Datei lautet %s", calcSHA1(text));
		
		//send_my_msg();
		
		//fclose(datei);
		
	//}
	
	return 0;
	
	











}

Mein Empfänger aktuell

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <arpa/inet.h>

int mySock, err, len, flen;

struct sockaddr_in addr,from;

char msg[100];



//Programm beenden mit timeout_error

void quitProgram() {
	
	printf(timeout_error);
	
	exit(0);
}

//Falsches Packet erhalten

void packageError() {
	
	printf(packet_error);
	
	exit(0);


int main(void) {
	
	mySock = socket(AF_INET,SOCK_DGRAM,0);
	
	if(mySock < 0) {
		
		printf("Socket konnte nicht erstellt werden");
	}
	
	addr.sin_family = AF_INET;
	addr.sin_port = htons(4711);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	err = bind(mySock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
	
	if(err <0) {
		
		printf("binding fehlgeschlagen");
	}
	
	flen = sizeof(struct sockaddr_in);
	
	len = recvfrom(mySock, msg, sizeof(msg), 0, (struct sockaddr *) &from, &flen);
	
	if(len < 0) {
		
		printf("Übertragungsfehler");
	}
	
	//printf("received %d Bytes from host %s port %d: %s", len, inet_ntoa(from.sin_addr), ntohs(from.sin_port), msg);






  return 0;

}

komme beim Schnüren der Pakte nicht weiter. Und beim Empfangen… etwas ungenaue Fragestellung ich weiss aber ich habe aktuell keine Idee wie ich weitermachen soll…

#2

Moin,

womit genau kommst du denn nicht weiter? Speziell beim Client fehlt ja noch ein ganzes Stück soweit ich das sehe.

Lässt du beim Server den socket listen und beim client connecten?

Wenn ja, gibts irgendwelche Fehlermeldungen?

Grüße

#3

listen und connect sind doch tcp und niht udp methoden ka was du damit meinst

#4

Stimmt, ich war Gedanklich bei TCP, entschuldige

#5

Wenn die Datei in Datenpaketen gesendet wird, sollte sie doch auch die Größe des Inhalts auch im Header mit der Sequenznummer befinden, oder? Und, hast du schon die maximale Paketgröße herausgefunden?

#6

Naja, auch ein UDP-Socket muss sich im Modus “listen” an einen Port binden damit dieser die Daten dann auch bekommt. Sonst wird das Paket vom Stack einfach verworfen.