/* * server.c - Parallel-Server-Programm * * Blatt 3, Aufgabe 1, Grundlagen der Informatik 2 fuer E-Techniker * SoSe 2002, (c) Jan Bredereke * * Der Server wartet auf eine eingehende Verbindung von Clients. * Kommt eine, macht er ein fork() und wartet auf weitere * Verbindungen, die andere Kopie speichert dann alle eingehenden * Daten in einer Datei mit dem Namen des Clients. Ende mit Strng-C. * * Parameter: Port des Servers. * * $Id: server.c,v 1.9 2002/06/26 11:58:23 brederek Exp $ */ #include #include #include #include #include #include #include #include #define QUEUE_LEN 5 #define BUF_SIZE 100 /* Kuemmert sich um eine eingegangene Verbindung. Kehrt nicht zurueck. */ void handleConnection(int sock, int childNum) { char puffer[BUF_SIZE+1]; int numRead; char dateiName[20]; FILE *datei; int retCode; /* Erzeuge Namen der Ausgabedatei */ sprintf(dateiName, "daten%d.txt", childNum); /* Oeffne Ausgabedatei */ datei = fopen(dateiName, "w"); if (datei == NULL) { perror("Kann Ausgabedatei nicht zum Schreiben oeffnen"); exit(1); } while(1) { /* Kopiere die Eingabe in die Ausgabe, solange Daten kommen */ numRead = read(sock, (void *) &puffer, BUF_SIZE); if (numRead == -1) { /* Wir nehmen an, dass alle Lesefehler "Dateiende" bedeuten. */ close(sock); fclose(datei); exit(0); } if(numRead) { puffer[numRead] = '\0'; retCode = fputs(puffer, datei); if (retCode == EOF) { perror("Datei-Schreibfehler aufgetreten"); exit(1); } printf("\n%s: %s", dateiName, puffer); } } } int main(int argc, char **argv) { int listenSock; int retCode; struct sockaddr_in serverAddr; struct sockaddr_in clientAddr; int clientAddrSize; int port; int dataSock; pid_t childPid; int childNum; int optval; /* Kommandozeile auswerten */ if (argc != 2) { fprintf(stderr, "Aufruf:\nserver \n"); exit(2); } retCode = sscanf(argv[1], "%d", &port); if (retCode != 1) { fprintf(stderr, "Unzulaessige Portnummer!\n"); exit(1); } /* Socket erzeugen */ listenSock = socket(AF_INET, SOCK_STREAM, 0); if (listenSock == -1) { perror("Server kann Socket nicht erzeugen"); exit(1); } /* Socket-Option einstellen: IP/Port-Adresse darf sofort wieder vergeben werden */ optval = 1; retCode = setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (void *) &optval, sizeof(optval)); if (retCode == -1) { perror("setsockopt() gescheitert"); exit(1); } /* Socket mit "Namen", d.h. mit Port verbinden */ memset((void *) &serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); serverAddr.sin_port = htons(port); retCode = bind(listenSock, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); if (retCode == -1) { perror("Server kann Port nicht binden"); exit(1); } /* Socket fuer eingehende Verbindungen aktivieren */ retCode = listen(listenSock, QUEUE_LEN); if (retCode == -1) { perror("Server kann nicht an Socket horchen"); exit(1); } /* Endlosschleife: Wartet staendig auf neue Verbindungen */ childNum = 0; while(1) { /* Eine eingehende Verbindung annehmen */ clientAddrSize = sizeof(clientAddr); dataSock = accept(listenSock, (struct sockaddr *) &clientAddr, &clientAddrSize); if (dataSock == -1) { perror("interner Fehler: accept() ging schief"); exit(1); } /* Anzahl der Verbindungen/Kinder hochzaehlen */ childNum++; /* Neuen Prozess fuer die eingegangene Verbindung erzeugen */ childPid = fork(); if(childPid == -1) { perror("Server kann keinen Kind-Prozess erzeugen"); exit(1); } /* Der Vaterprozess beginnt sofort wieder zu warten, ... */ if(childPid == 0) { /* ... der Kind-Prozess kuemmert sich um die Verbindung. */ handleConnection(dataSock, childNum); /* Dieser Aufruf kehrt nicht zurueck. */ } } }