Beispiel Block 1

Werbung
Beispiel Block 1 Programmierrichtlinien und Fehlerbehandlung Argumentbehandlung Stream I/O Signale Sockets Übungsaufgaben Benedikt Huber
SS 2012
1 Übungsbeispiel 1 Allgemeines Programmerstellung 2 Entwicklung der Übungsbeispiele
•  Konventionen Programmerstellung
•  Verwendung von Makefiles
•  Übersetzten mit –Wall
•  Konventionen Argumentbehandlung
•  Verwenden von getopt
•  “Usage” Meldungen
•  Konventionen Fehlerbehandlung und Exitcode
•  Abfragen von Rückgabewerten
•  Ausgabe von Fehlern und Beenden des Programms
3 Programmerstellung
a.h
b.h
x.c
y.c
•  Makefiles verwenden
•  make all, make clean
•  Abhängigkeiten spezifieren
•  Übersetzen
•  -c … Übersetzen
•  -Wall … Aktivieren aller Warnungen
•  -g ... Informationen für Debugger
•  Linken
•  Objektdateien  ausführbare Datei
Übersetzer
x.o
y.o
Linker
executable
4 Programmerstellung (2)
•  Konfigurieren des Übersetzers
•  C99 Standard
CC=gcc
CFLAGS=-std=c99 –pedantic –g –Wall \
-D_XOPEN_SOURCE=500 –D_BSD_SOURCE
•  Abhängigkeiten
•  Steuern inkrementelle Übersetzung
•  Extrahieren von Abhängigkeiten mit gcc –M
hello.o: hello.c hello.h
5 Programmerstellung (3)
•  Verwendung automatischer Variablen
executable: $(OBJECT_FILES)
$(LD) $(LDFLAGS) –o $@ $^
%.o: %.c
$(CC) $(CFLAGS) –c –o $@ $<
•  Entfernen automatische erstellter Dateien
clean:
rm –f $(OBJECT_FILES) executable
.PHONY: clean
6 Übungsbeispiel 1 Argumentbehandlung Fehlerbehandlung 7 Argumentbehandlung
•  Shell-Kommandos bestehen aus
•  Programmnamen, oder Pfad zur ausführbaren Datei
•  Optionen: steuern wie das Kommando angewendet wird.
• 
Auch Optionen können Argumente besitzen.
Argumenten: Objekte, auf die das Kommando
angewendet werden soll (Dateien, Verzeichnisse, etc.)
•  Beispiel:
ls –l -a
Optionen
/usr/local/bin /usr/bin
Argumente
8 Argumentbehandlung
POSIX-Konventionen (1)
•  Optionen vor restlichen Programmargumenten
•  Option Kurzform: „-“ gefolgt von einem Zeichen
•  Beispiel: -c
•  Zusammenfassen mehrerer Optionen möglich (-la)
•  Option Langform: Zeichenkette folgend „--“
•  Beispiel: --dry-run
•  Reihenfolge der Optionen üblicherweise belanglos
[1] hLp://pubs.opengroup.org/onlinepubs/9699919799/ 9 Argumentbehandlung
POSIX-Konventionen (2)
•  Argumente zu Optionen
•  Bsp: hallo -a optarg1 -c arg1 arg2
•  Bsp: hallo --user=max arg1 arg2
•  Ende der Optionsliste:
•  Zeichenkette ist (a) kein Argument einer Option und (b)
beginnt nicht mit “-” bzw. “--”
Zeichenkette “--”, nicht als Argument einer Option
• 
•  Optionen dürfen in der Regel maximal einmal
auftreten
•  Bsp: hallo -c -c arg1 # Fehler
10 Argumentbehandlung
Dokumentation (man pages)
•  Optionale Angaben durch [] gekennzeichnet
hallo -a optarg [-o] arg1
•  Abhängigkeiten von Optionen
hallo [-a optarg [-o]] arg1
•  Alternative Optionen durch [x|y]
hallo [-a optarg| -o] arg1
•  Ein oder mehrere Vorkommen eines Arguments
hallo –arg optarg file...
11 Argumentübergabe an main (1/2)
int main(int argc, char **argv)
•  argc ... Anzahl der Elemente von argv
•  argv ... Array von Kommandozeilenparametern (argv[0]... argv[argc-1])
argv h
a
l
l
o
\0
-
a
\0
a
r ...
12 Argumentübergabe an main (2/2) •  Welchen Wert hat argc?
hallo
hallo
hallo
hallo
test
-a argZuOpt
–a argZuOpt -o test
–a argZuOpt “–o test“
13 Argumentübergabe an main (2/2) •  Welchen Wert hat argc ?
•  Anzahl Kommandozeilenparameter + 1 hallo
hallo
hallo
hallo
test
-a argZuOpt
–a argZuOpt -o test
–a argZuOpt “–o test“
2
3
5
4
14 getopt (1/2)
•  Zur Optionsbehandlung wird die Funktion getopt
verwendet (Langform: getopt_long)
•  Parameter für getopt
•  argc, argv, Spezifikation der gültigen Optionen
•  Aufgaben des Programmierers
•  Vorkommens einer Option zählen
•  Behandlung von ungültigen Optionen
•  Speichern von Optionsargumenten
•  Überprüfung der korrekten Argumentzahl
15 getopt Beispiel
int c;
while( (c = getopt(argc, argv, “a:o”)) != -1 ){
switch( c ){
case ‘a’:
/* Option mit Argument */
break;
case ‘o’:
/* Option ohne Argument */
break;
case ‘?’:
/* ungültiges Argument */
break;
default:
/* unmöglich */
assert( 0 );
}
}
16 getopt: Zählen von Optionen
int opt_o = 0;
...
case ‘o’:
opt_o++;
break;
...
...
if( opt_o > 1 ) /* max. 1 Mal */
usage();
if( opt_o != 1 ) /* oder: genau 1 Mal */
usage();
17 getopt: Argumente zu Optionen
char *input_file = NULL;
while( (c = getopt(argc, argv, “a:o”)) != -1) {
switch( c ) {
case ‘a’:
/* optarg: Zeiger auf Optionsargument */
input_file = optarg;
break;
...
}
}
18 Weitere Informationen: man pages
•  Beispielreferenz auf man‐page: getopt(3) •  Bedeutung: “Die Informa-onen finden sie in den man pages zu getopt in • 
• 
• 
• 
Abschni: 3“ Lesen der manpage unter Linux: "man 3 getopt" Verschiedene man‐Pages mit dem gleichen Themen‐Namen: •  getopt(1) der Shell‐Befehl •  getopt(3) das C‐Kommando Kommandozeilenprogramme in AbschniL 1 C‐Kommandos in AbschniL 2 (Systemaufrufe), 3 (Bibliotheksaufrufe) und 7 (Verschiedenes) 19 Übungsbeispiel 1 Fehlerbehandlung Signalbehandlung 20 Umgang mit Fehlern (1/2)
•  Fehlervermeidung durch Programmierstil
•  Fehlermeldungen auf stderr
•  Rückgabewert von Funktion immer abfragen
•  Ausnahme: Bei Ausgabe auf stderr
•  Beim Auftreten eines Fehlers
•  Recovery – Strategie
•  In dieser LVA: ordnungsgemäßes Terminieren (alle
Ressourcen schließen, ...)
21 Umgang mit Fehlern (2/2)
•  Aussagekräftige Fehlermeldungen
•  Probleme in welchem Programm? (argv[0])
•  Welche Probleme? (z.B. fopen failed)
•  Ursache? (strerror(errno))
•  Terminieren des Programms
•  Freigeben von Ressourcen (z.B. temporäre Dateien)
•  Exitcode (EXIT_SUCCESS, EXIT_FAILURE)
22 Usage-Meldungen
char *command= “<not set>“;
int main (int argc, char *argv[]) {
if(argc>0) command = argv[0];
...
}
void usage(void) {
(void) fprintf(stderr,“Usage: %s [-a arg] arg1”,
command);
exit(EXIT_FAILURE);
}
23 Signale
•  Signal ... asynchrone Prozessbenachrichtigung
•  Beispiele
•  Speicherschutzverletzung (SIGSEGV)
•  Interrupt vom Keyboard (SIGINT, <Ctrl>-C)
•  Abruptes Beenden eines Prozesses (SIGKILL)
•  Beenden eines Servers
•  Erzeugen von Signalen
•  kill 1521 (SIGTERM)
•  kill -9 1521 (SIGKILL)
•  man 7 signal
24 Signalbehandlung
•  Signalbehandlung
•  Für viele Signale kann Reaktion des Programms
• 
• 
konfiguriert werden (Ausnahmen: SIGKILL,...)
Optionen: Ignorieren, Terminieren, eigene Routine
Unter Linux wird sigaction zum Konfiguieren der
Signalbehandlung empfohlen
•  Betriebssystemroutinen
•  Signale unterbrechen Ausführung von
• 
• 
Betriebssystemroutinen
Option 1: Transparenter Neustart (BSD Semantik)
Option 2: Fehlercode EINTR (SysV Semantik)
25 Signalbehandlungroutinen
•  C-Funktion, Signalnummer als Parameter
void cleanup(int signal) {
/* free ressources and terminate */
}
•  Einschränkungen
•  Kommunikation mit eigentlichem Programm über speziell
• 
• 
definierte Variablen (volatile sig_atomic_t)
Nur bestimmte Funktionen sind zugelassen
Signal kann durch weiteres Signal unterbrochen werden
(Abhilfe: sigprocmask)
26 Signalbehandlung konfigurieren
•  Signal mit Routine verbinden
• 
• 
• 
• 
Signalbehandlungsroutine
Behandeln von unterbrochenen Betriebssystemroutinen
Blockieren von weiteren Signalen
Siehe man 2 sigaction
struct sigaction s;
s.sa_handler = cleanup;
memcpy(&s.sa_mask, &blocked_signals,
sizeof(s.sa_mask));
s.sa_flags
= SA_RESTART;
sigaction(SIGINT, &s, NULL);
27 Signalbehandlungsroutinen (2)
•  Globale Variablen im Signalhandler
volatile sig_atomic_t count;
void signal_handler_count(int signal){
count++;
}
•  Synchronisation
•  Signalbehandlungsroutine soll u.U. nur einmal
• 
ausgeführt, oder an einer kritischen Stelle nicht
unterbrochen werden
 Vorrübergehendes Deaktivieren von Signalen
28 Übungsbeispiel Block 1 Stream I/O Christian El Salloum
SS 2010
29 Aufbau des Dateisystems (Linux)
  Hierarchische Struktur / von Dateien   Verschiedenste Dateitypen in einer gemeinsamen Verzeichnisstruktur: „everything is a file“ - 
- 
- 
- 
- 
- 
/bin commands /lib /dev devices /etc /usr /var startup and configuracon files /man /local plain files (stream of characters) directories (Interpretacon durch das OS) character‐, block special files (Geräte; z.B. Terminal, FestplaLe) named pipes sockets (z.B. TCP/IP sockets, UNIX domain sockets) symbolic links (Verweise) 15.03.12 30 Mounten von Dateisystemen   Zusammenfassen mehrerer File‐Systeme in einer Verzeichnisstruktur   Eingebundenes Dateisystem ist entweder: -  lokal verfügbar (z.B. untersch. Parccon oder FestplaLe, Wechseldatenträger), -  verfügbar via Netzwerk (z.B. über NFS), -  oder befindet sich selbst in einem File (z.B. loop device für ISO‐Images)   Vorteil: untersch. Filesysteme gleichzeicg verwendbar 15.03.12 31 Virtuelles Filesystem (VFS)   > 15 physikalische Filesysteme unter Linux in Verwendung -  Kompacbilität zu anderen Systemen (z.B. NTFS, FAT) -  Sicherheit, Zuverlässigkeit der Daten (z.B. Ext3, ReiserFS) -  Performance (z.B. XFS)   Einführung einer zusätzlichen Abstrakconsebene -  einheitliche SchniLstelle -  transparentes Mounten verschiedener physikalischer Dateisysteme (Parcconen) in eine Directory‐Struktur 15.03.12 32 File Descriptors
  Verweis auf Eintrag in Tabelle offener Dateien (file descriptor table, Teil des aktuellen Prozesses)   Standard I/O   STDIN_FILENO = 0 (Standardeingabe)   STDOUT_FILENO = 1 (Standardausgabe)   STDERR_FILENO = 2 (Fehlerausgabe)   Siehe auch: fileno(stdin), fileno(stdout), ...   Funkconen: open(2), close(2), read(2), write(2),... 33
Stream IO in C
  Stream IO baut auf File‐Deskriptoren auf  
 
 
 
  #include <stdio.h> Stream Datentyp: FILE Gepuffert (siehe fflush(3)) Konvencon: Befehle beginnen mit ‚f‘ fopen(3), fdopen(3), fwrite(3), fprinA(3), … stdin, stdout, stderr sind vordefinierte Streams S t r eam I O
Puf f er
IO
OS
34
fopen(3)
FILE *fopen(const char *path, const char *mode); Die Datei path wird geöffnet, und mit Stream (Rückgabewert) verbunden mode: „r“
nur lesen “w“ nur schreiben (exiscerenden Inhalt löschen) “a“ nur schreiben (am Ende anhängen) „r+“/“w+“/“a+“ lesen und schreiben 35
fdopen(3)
FILE *fdopen(int fildes, const char *mode); Assoziiert einen Stream mit einem Filedescriptor FILE* f; int fd; int fd = socket(AF_INET, SOCK_STREAM,0); … f = fdopen(fd, “r+“); fprintf(f,“Meine Prozess‐ID ist: %d\n“, getpid()); 36
fflush(3), fclose(3)
int fflush(FILE *stream); int fclose(FILE *stream);   fflush erzwingt das Schreiben von gepufferten Daten   fclose ruv fflush auf und schließt den Stream sowie den zugrundeliegenden Deskriptor. 37
Lesen/Schreiben
Funk-on fread Lesen von n Elementen a size Bytes fgets Lesen einer Zeile fgetc Lesen eines Zeichens fwrite Schreiben von n Elementen a size Bytes fputs Schreiben eines C‐Strings fprinx Formacertes Schreiben fputc Schreiben eines Zeichens fseek Posiconieren des Dateiposiconszeigers 38
ferror(3), feof(3)
int ferror(FILE *stream); int feof(FILE *stream); int clearerr(FILE *stream);   ferror ergibt den Fehlerstatus des Streams zurück (0 ~ error flag nicht gesetzt).   feof fragt ab, ob das End‐Of‐File Flag des Streams gesetzt ist (wird beispielsweise von fgets gesetzt, wenn das Ende der Datei erreicht wird)   clearerr löscht Fehlerstatus und EOF Flag 39
Stream I/O Beispiel
#define SIZE 512 int main(int argc, char **argv) { char buffer[SIZE]; FILE *f; … f = fopen(argv[1],“r“); while (fgets(buffer,SIZE,f) != NULL) { fputs(buffer,stdout); } if (ferror(f)) { bail_out(“IO Error“); } return 0; } 40
Übungsbeispiel Block 1 Sockets Christian El Salloum
SS 2010
41 Sockets
  Was sind Sockets? •  Kommunikaconsmechanismus (nicht verwandte Prozesse, verschiedene Maschinen) Kommunikaconsendpunkt • 
  Client und Server kommunizieren durch Lesen von und Schreiben auf den Dateideskriptor, der dem Socket zugeordnet ist Socket API
  Üblicherweise Schnittstelle zur Transportschicht
eines Kommunikationsprotokolls
• 
• 
• 
• 
• 
• 
Application Layer (HTTP, SMTP)
Socket API
Transport Layer (TCP, UDP)
Socket API (Raw Sockets)
Network Layer (IP, ARP)
Link Layer (Ethernet Driver)
Sockets (2)
  Adressfamilie (Network Layer)
•  AF_INET (IP), AF_INET6  man 7 ip
•  Unix Domain Sockets (Lokale
Interprozesskommunikation)  man 7 unix
  Verbindungsorientierte Sockets
•  SOCK_STREAM, Default für IP ist TCP
•  Verbindung wird eindeutig durch zwei Endpunkte
identifiziert
  Verbindungslose Sockets
•  SOCK_DGRAM, Default für IP ist UDP
Client/Server
TCP/IP Protokoll
  Client und Server kommunizieren über das
Senden und Empfangen von Bytefolgen
  Eigenschaften: Verbindungsorientiert, vollduplex,
zuverlässig
Endpunkt Clientseite
Endpunkt Serverseite
Client IP + freie Portnummer Server IP +
Client
Client host address
Client IP
Connection socket pair
Server
(port 80)
Server host address
Server IP
Client-Server Beispiel
Server Socket() Bind() Client Listen() Blockiert bis Verbindung hergestellt Accept() Recv() Send() Socket() Verbindungsau{au Connect() Daten (Anfrage) Send() Daten (Antwort) Recv() 46 System Call: socket
  Erstellt einen Kommunikationsendpunkt (Socket)
int socket(int family, int type, int protocol)
  family: Adressfamilie (Protokollfamilie)
•  e.g. AF_UNIX, AF_INET
  type: Art der Socketkommunikation
•  e.g. SOCK_STREAM, SOCK_DGRAM
•  Nicht alle Kombinationen von Protokollfamilie und Typ
werden unterstützt
  protocol: zu verwendendes Kommunikationsprotokoll
•  Protokollfamilie + Typ implizieren üblicherweise Protokoll
•  0  Default-Protokoll
  Rückgabewert: Handle des neu erstellten Socket
Client-Server Beispiel
Server Socket() Bind() Client Listen() Blockiert bis Verbindung hergestellt Accept() Recv() Send() Socket() Verbindungsau{au Connect() Daten (Anfrage) Send() Daten (Antwort) Recv() 48 System Call: bind
  Ordnet dem neu erstellten Socket eine bestimmte
Adresse zu
int bind(int socket,
struct sockaddr *address,
socklen_t addr_len)
  Socket: identifiziert den neu erstellten Socket
  Address: Datenstruktur mit lokaler Adresse
Socket Address Format
  Generische Datenstruktur für Socket - Adressen:
•  Argumente zu connect, bind, und accept
struct sockaddr { unsigned short sa_family; /* protocol family */ char sa_data[14]; /* address data. */ };   IP – spezifische Datenstruktur:
•  (sockaddr_in *) muss auf (sockaddr *) gecastet werden
struct sockaddr_in { unsigned short sin_family; /* address family (always AF_INET) */ unsigned short sin_port; /* port num in network byte order */ struct in_addr sin_addr; /* IP addr in network byte order */ unsigned char sin_zero[8]; /* pad to sizeof(struct sockaddr) */ }; Client-Server Beispiel
Server Socket() Bind() Client Listen() Blockiert bis Verbindung hergestellt Accept() Recv() Send() Socket() Verbindungsau{au Connect() Daten (Anfrage) Send() Daten (Antwort) Recv() 51 System Call: listen
  Bei verbindungsorientierten Protokollen: Server ist bereit
Verbindungen anzunehmen
int listen(int socket, int backlog)
  socket: identifiziert den neu erstellten Socket
  backlog: Anzahl an Verbindungsanfragen die vom
Betriebssysteme in einer Warteschlange verwaltet werden,
bis der Server die Verbindungen annimmt (Richtwert: 5)
Client-Server Beispiel
Server Socket() Bind() Client Listen() Blockiert bis Verbindung hergestellt Accept() Recv() Send() Socket() Verbindungsau{au Connect() Daten (Anfrage) Send() Daten (Antwort) Recv() 53 System Call: accept
  Warten auf eingehende Verbindungen (passiver
Verbindungsaufbau)
int accept(int socket,
struct sockaddr *address,
socklen_t *addr_len)
  Blockiert bis zu einer Verbindungsanfrage eines Clients
  Rückgabewert ist ein Socket für die aufgebaute Verbindung
(ein Dateideskriptor)
System Call: connect
  Aktiver Verbindungsaufbau (Client)
int connect(int socket,
const struct sockaddr *address,
socklen_t addr_len)
  Kehrt nach dem Handshake zum Aufrufer zurück
  address spezifiert die Adresse des Servers
  Das Betriebssystem des Clients wählt üblicherweise
beliebigen, nicht verwendeten Port
System Call: send and recv
  Nach dem Verbindungsaufbau können Daten
versendet und empfangen werden
  Senden einer Nachricht über den spezifizierten
Socket
int send(int socket, const void *msg,
size_t msg_len, int flags)
  Empfangen einer Nachricht vom spezifizierten
Socket
int recv(int socket, void* buf,
size_t buf_len, int flags)
System Call: send and recv
  Rückgabewert: Anzahl empfangener/versendeter
Bytes
•  Möglicherweise weniger Bytes übertragen als
• 
angefordert
Schleife notwendig
Übungsbeispiel Block 1 Übungsaufgaben Christian El Salloum
SS 2010
58 1. Übungsbeispiel
  1a: Implementierung eines einfachen UNIX Tools
  Kennenlernen der Programmiersprache C
  Argumentbehandlung
  Kennenlernen von Makefiles
  1b: Server und Client für „mastermind“
  Kommunikation via Sockets
  Implementierung eines einfachen Protokolls
  Source – Code für Server ist zum Teil vorgegeben
  Optional: Entwicklung einer Spielstrategie in C
15.03.12 1.Übungsbeispiel 59 Abwicklung des Spiels
 
 
 
 
 
1 Server, 1 Clients
Kommunikation via TCP/IP Sockets
Ziel: Erraten der geheimen Farbfolge
Client übermittelt vermutete Folge (2 Byte)
Server antwortet mit einem Byte
  Anzahl korrekt positionierter Farben
  Anzahl falsch positionierter Farben
  Statusflags (Ende des Spiels, Paritätsfehler)
  Einfaches binäres Protokoll
15.03.12 1.Übungsbeispiel 60 Ende des Spiels
  Spieler errät die Geheimfolge
  Ausgabe Anzahl gespielter Runden
  Erreichen der maximalen Anzahl von Runden
(Server signalisiert Ende des Spiels)
  Paritätsfehler (z.B. falsch berechnet)
  Andere Fehler (z.B. Verbindungsfehler)
15.03.12 1.Übungsbeispiel 61 Bewertung: Korrekte Clients/Server
  Protokoll korrekt implementiert
 
 
 
 
 
 
  Einhalten der maximalen Antwortzeit (1 Sekunde)
Korrekte Berechnung der Serverantwort
Terminieren mit dem korrekten Exitcode
Ausgabe der korrekten Anzahl gespielter Runden
Korrekte Argumentbehandlung
Korrekte Signalbehandlung
Einhaltung der Richtlinien zu den
Übungsbeispielen
15.03.12 1.Übungsbeispiel 62 Spielstrategien
  Optional: Implementierung von Spielstrategien
  Tipp: Einfacher Algorithmus gewinnt stets in 34 Zügen
  Bonuspunkte für gute und ausgezeichnete
Implementierungen
  Gut (+5): Gewinnstrategie, im Schnitt 20 oder weniger
 
Runden
Ausgezeichnet (+10): Gewinnstrategie, im Schnitt 8 oder
weniger Runden
  Viel Spass 
15.03.12 1.Übungsbeispiel 63 
Herunterladen