[Cheatsheet] CODE-SAMMLUNG

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

[Cheatsheet] CODE-SAMMLUNG
b FINALER STAND!![/b]

Hallo Leute,

ich habe mir heute ein paar Minuten genommen, um die wichtigsten Code-Schnipsel für das Cheatsheet in Form zubringen.
Bitte kommentiert bei Fehlern oder falls ich wichtige Code-Segmente übersehen habe!

LESEN DER ZEILEN VOM CLIENT (Stand: 19. Feb, 11:43 AM)

char buffer[MAX_LINE_LEN+1];
if(fgets(buffer, sizeof(buffer), rx) == NULL) return -1;
char *nach;
char *vor;
if((vor = strtok(buffer, "delimiter")) == NULL) return -1;
if((nach = strok(NULL, "\n")) == NULL) return -1;
if(strcmp(vor, "something")) {
    //... do something
}
return -1;

THREADS (Stand: 19. Feb, 11:15 AM)

phtread_t tid;
for(int i = 0; i < MAX_CLIENTS; i++) {
    if(pthread_create(&tid, NULL, &somefunction, NULL) != 0) die("pthread_create");
    
    //Auf Thread warten, Ressourcen freigeben und Rückgabewert abfragen: join
    if(pthread_join(&tid, NULL) != 0) die("pthread_join");
    
    //Ressourcen automatisch bei Beendigung freigeben
    if(pthread_detach(&tid) != 0) die("pthread_detach");
}

DURCHSUCHUNG VON VERZEICHNIS (READDIR) (Stand: 19. Feb, 11:10 AM)

DIR *dir = opendir(path);
if(!dir) {
	perror("opendir");
	exit(EXIT_FAILURE);
}

struct dirent *dir_entry;
struct stat buf;
while(errno = 0, (dir_entry = readdir(dir)) != NULL) {
	if((lstat(dir_entry->d_name, &buf) == -1) || !IS_ISREG(buf.st_mode)) {
		continue;
	}
	//... do something
	if(errno != 0) perror("errno");
	if(closedir(dir) == -1) perror("closedir");
}

STARTEN VON PROZESSEN (Stand: 19. Feb, 10:44 AM)

for(int i = 0; i < MAX_PROCESS_COUNT; i++){
    pid_t pid = fork();
    if (pid == (pid_t) 0) { //child
        //... do something
    } else if (p != (pid_t) -1) { //parents
        //... do something
    } else {
        perror("fork");
    }
}

SIGNALBEHANDLUNG (Stand: 19. Feb, 10:15 AM)

static sigset_t block;
sigemptyset(&block);
struct sigaction action = {
	.sa_handler = sighandler | SIG_IGN | SIG_DFL,
		/* 	sighandler = selbst geschriebene Signalbehandlung
			SIGN_IGN: Signal ignorieren 
			SIG_DFL: Standard-Signalbehandlung einstellen */
	.sa_mask = block,
	.sa_flags = SA_RESTART | SA_NOCLDSTOP
		/* 	SA_NOCLDSTOP: SIGCHLD wird nur zugestellt, wenn ein Kindprozess terminiert, nicht wenn er gestoppt wird
			SA_RESTART: durch das Signal unterbrochene Systemaufrufe werden automatisch neu aufgesetzt */
};
if (sigaction(SIGCHLD, &action, NULL) == -1) die("action");
sigaddset(&block,SIGCHLD);

BLOCKIERUNG VON SIGNAL (Stand: 19. Feb, 10:15 AM)

sigset_t old, new;
sigemptyset(&new);
sigemptyset(&old);
sigaddset(&new, SIGCHLD);
sigprocmask(SIG_BLOCK, &new, NULL);
//... do something
sigprocmask(SIG_SETMASK, &old, NULL);

WARTEN AUF SIGNAL (Stand: 19. Feb, 10:18 AM)

sigset_t new, old;
sigemptyset(&new);
sigemptyset(&old);
sigaddset(&new, SIGCHLD);
sigprocmask(SIG_BLOCK, &new, NULL);
//(optional: do something)
while (!condition) {
	sigsuspend(&old);
}
//(optional: do something)
sigprocmask(SIG_SETMASK, &old, NULL);

SIGNAL-HANDLER (Stand: 19. Feb, 10:18 AM)

int old_errno = errno;
while (waitpid(-1, NULL, WNOHANG) != -1) {
    threadcounter--;
    //(optional: do something)
}
errno = old_errno;

SERVER: SOCKET ERSTELLEN, VERBINDUNGSANNAHME VORBEREITEN UND VERBINDUNGSANNAHME (Stand: 19. Feb, 9:40 AM)

int listenSock = socket(AF_INET6, SOCK_STREAM, 0);
if(listenSock==-1) die("socket");
struct sockaddr_in6 name = {
    .sin6_family = AF_INET6,
    .sin6_port   = htons(port),
    .sin6_addr   = in6addr_any,
};

int flag = 1
if (0 != setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag))) die("setsockopt");
if(-1 == bind(listenSock, (struct sockaddr *) &name, sizeof(name))) die("bind");
if(-1 == listen(listenSock, SOMAXCONN)) die("listen");

for (;;) {
    int clientSock = accept(listenSock, NULL, NULL);
	if (-1 == client_sock) {
            perror("accept");
            continue;
        }
   	//... do something
    close(clientSock);
}

CLIENT: SOCKET ERSTELLEN UND DNS-ANFRAGE (Stand: 19. Feb, 9:45 AM)

char *host, *port;
struct addrinfo hints = {
	 .ai_socktype = SOCK_STREAM, 
	 .ai_family = AF_UNSPEC, 
	 .ai_flags = AI_ADDRCONFIG, 
}; 
struct addrinfo *head;
int err = getaddrinfo("xkcd.com", "80", &hints, &head);
if (err != 0) {
	if (err = EAI_System) {
		fperror("getaddrinfo");
	}
	else {
                fprintf(stderr, getaddrinfo: "%s", gai_strerror(err))
	}
}

int sock;
for (curr = head; curr != NULL; curr = curr->ai_next) {
	sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
	if (sock == -1) continue;
	if (connect(sock, curr->ai addr, curr->ai addrlen) == 0) break;
        close(sock);
}
if (curr == NULL) {
    exit(EXIT_FAILURE);
}

FILE* ZUM LESEN UND SCHREIBEN (thread_handler()) (Stand: 19. Feb, 9:52 AM)

for(;;) {
    int sock = bbGet();
    FILE *rx = fdopen(sock, "r"); 
    if (!rx) {
        close(sock);
        continue;
    }
    int sock2 = dup(sock);
    if (sock2 < 0) {
        close(sock);
        continue;
    }
    FILE *tx = fdopen(sock2, "w"); 
    if(!tx) {
        fclose(rx); 
        close(sock2); 
        continue;
    }
    doWork(rx, tx);
    fclose(rx);
    fclose(tx);
		
    /* ggf. Erstellung eines zwei-dimensionalen Arrays 
    FILE **farray = calloc(2, sizeof(FILE *)); 
    if (farray) {
	farray[0] = rx;
	farray[1] = tx; 
    } */
}

SEMAPHOR (Stand: 19. Feb, 9:20 AM)
(Lösung für Übungsaufgabe entfernt --iridium)

JBUFFER (Stand: 19. Feb, 9:30 AM)
(Lösung für Übungsaufgabe entfernt --iridium)

7 „Gefällt mir“

An dieser Stelle folgender Hinweis (da die Frage nach der Klausur gerne mal kommt):
Wir sammeln die Cheatsheets mit der Klausur ein; dementspr. ist es ratsam, sich vor der Klausur eine Kopie des Cheatsheet fuer die private Sammlung zu machen :wink:

3 „Gefällt mir“

Weshalb sammelt ihr die ein? Ihr könnt mein geschmier doch eh nicht lesen.


Dann bist du gezwungen, in dem unwahrscheinlichen Fall, dass du durchfällst, zumindest nochmal einen Zettel zu schreiben als Vorbereitung. Außerdem kommen die besten Exemplare in die ewige Sammlung.

2 „Gefällt mir“

Ich hätte eine Frage zu den Code-Schnipseln:

Unter SIGNALBEHANDLUNG habe ich folgendes geschrieben:

sigemptyset(&action.sa_mask);
if (sigaction(SIGCHLD, &action, NULL) == -1) die("action");
sigemptyset(&block);
sigaddset(&block,SIGCHLD);

Ist hier die Zeile 1, sprich: sigemptyset(&action.sa_mask);, doch nicht eigentlich falsch/überflüssig?


Wenn ich das in dem Gesamtkontext oben sehe, verwendest du [m]block[/m] ja als [m]action.sa_mask[/m]. Um die Änderungen, die durch das [m]sigemptyset/sigaddset[/m] (Zeile 3 + 4) an der Maske vorgenommen werden, auch im Rahmen der Signalbehandlung aktiv zu haben, musst du das vor dem Aufruf von [m]sigaction()[/m] machen - der Betriebssystemkern kopiert sich die von dir übergebenen Daten nämlich in sein eigenes Format weg und beobachtet die Struktur in deinem Programm danach nicht mehr.

Dann ist das auch nicht mehr redundant :wink:


Ich hab meinen Code auch mal etwas gesammelt, vielleicht findet der ein oder andere ja noch etwas Hilfreiches: https://github.com/Clubfan22/SP-Snippets

1 „Gefällt mir“

FYI: Ich update meine Code-Schnipsel im Laufe des heutigen Tages basierend auf deinen Snippets.
Vielleicht kannst du bei Fehlern oder anderen Anmerkungen Feedback geben.


Ich hatte noch einen Fehler im rekursiven Verzeichnisdurchlauf, das sollte jetzt behoben sein: https://github.com/Clubfan22/SP-Snippets/commit/7b420671b0fc8c3bb4f0dd2445444dd0711bd32b


[1] "If the argument oset is not NULL, the previous mask is stored in the space pointed to by oset.’

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

Bloss nicht die Fehlerabfrage fuer sigemptyset() vergessen!


Wichtig: Da [m]strtok()[/m] nicht threadsicher ist, funktioniert das nur in einfädigen Programmen.

Das [m]&[/m]-Zeichen in Zeile 3 ist optional. Die Zeilen 6 und 9 sind Alternativen (ich glaube, in der Klausur hat jemand tatsächlich Beides hingeschrieben :-p).

Die [m]errno[/m]-Abfrage in Zeile 14 muss nach der Schleife erfolgen.

Wichtig: Der Kindprozess muss terminieren, sonst baut man sich eine Fork-Bombe.

Warum die Variable in Zeile 1 als [m]static[/m] deklariert ist, erschließt sich mir nicht.
Das [m]sigaddset()[/m] in Zeile 14 ist gleich doppelt unnötig. Einerseits hat es sowieso keine Auswirkung, weil es erst nach dem Zusammenbauen der Struktur und dem Aufruf von [m]sigaction()[/m] stattfindet; andererseits ist während der Signalbehandlung das auslösende Signal immer implizit blockiert.

Anstatt in Zeile 3 die alte Signalmaske explizit zu initialisieren, sollte man sie lieber in Zeile 5 einen Zeiger darauf als Ausgabeparameter übergeben. Das macht den Code weniger fehleranfällig, wenn man im Programm noch mit weiteren Signalen jongliert.

Selbiges gilt hier.

Dieser Code kompiliert nicht, weil ein Strichpunkt fehlt. :wink:

In Zeile 11 sollte [m]perror()[/m] stehen; Zeile 14 kompiliert wegen zweier Syntaxfehler nicht - und die Fehlermeldung schaut auf der Konsole komisch aus, weil der Zeilenumbruch fehlt.

Bitte depubliziere den Semaphor- und Ringpuffer-Code sowohl aus dem Forum als auch von GitHub - das ist Lösungscode für Übungsaufgabe 4. Wir hatten dieses Semester in den Übungen schon genug mit Studenten zu kämpfen, die dreist plagiiert haben.

Ihr wollt nicht, dass wir auch in SP anfangen rumzuostern, oder? :smiley:

5 „Gefällt mir“

Desweiteren sollte das Schließen des Directory Streams in Zeile 15 aus der Schleife raus.

Desweiteren wurde in Zeile 10 vermutlich = anstatt == verwendet.
Und am Schluss nicht vergessen die verlinkte Liste die getaddrinfo zurückliefert wieder zu freen! (mittels freeaddrinfo(3))
Die Deklaration von curr fehlt. Typ sollte struct addrinfo * sein.
Zeile 10 die Konstante müsste EAI_SYSTEM heißen (Als Daumenregel: Skalare Konstanten sind meistens FULL CAPS)


Das setsockopt um SO_REUSEADDR zu setzen sollte in der Klausur nicht nötig sein(!? Korrigiert mich bitte falls dies nicht zutrifft).
(Grund: siehe https://www4.cs.fau.de/Lehre/WS18/V_SP2/Uebung/Folien/U02.pdf Folie 12)


Die Option SO_REUSEADDR ist bei Servern gebräuchlich, aber sicherlich nicht als Pflicht anzusehen. Insbesondere, da es unter verschiedenen Systemen verschiedenes Verhalten erzeugt.


Vor der for-schleife muss curr noch angelegt werden! struct adrrinfo *curr;


Sicher? Wenn ich das &-Zeichen vor tid weglassen bekomme ich einen error:
error: passing argument 1 of ‘pthread_create’ makes pointer from integer without a cast [-Werror=int-conversion]


Das andere & vor somefunction ist gemeint.

3 „Gefällt mir“

Bei [m]readdir[/m], sollte doch das [m]closedir[/m] und [m]errno != 0[/m] nach der Schleife geschrieben werden, oder nicht?