3. Στο ίδιο μηχάνημα:
Pipes, σήματα, μηνύματα, global memory, αρχεία
Σε διαφορετικά μηχανήματα
Named pipes (FIFOs)
sockets
IIOP (CORBA, OO wrappers για sockets)
COM+(Win32)
Mail-slots(Win32)
Web Services
3
4. Ανοίξτε ένα x-terminal και τρέξτε την εντολή
$ ls –l | wc –l
Τι θα συμβεί?
Στο Α’ μέρος του σημερινού μαθήματος θα εξηγήσουμε πως ακριβώς
υλοποιούνται όλα αυτά σε επίπεδο λειτουργικού συστήματος
Pipe: ειδικός τύπος αρχείου FIFO που χρησιμοποιείται
για την σειριακή μεταφορά δεδομένων μεταξύ δύο διεργασιών,
προς μια κατεύθυνση
Μπορεί να είναι είτε μόνιμο (δηλαδή με όνομα)
είτε προσωρινό
4
6. int pipe(int fd[]);
Η κλήση pipe() λαμβάνει ως παράμετρο ένα array fd δύο ακεραίων και επιστρέφει δύο file
descriptors
Το fd[0] READ , προσδιορίζει το άκρο του pipe από όπου διαβάζουμε
Το fd[1] WRITE, προσδιορίζει το άκρο στο οποίο γράφουμε
Τα στοιχεία που γράφονται στο ένα άκρο της σωλήνωσης
μπορούν να διαβαστούν από το άλλο.
Τα μη χρησιμοποιούμενα άκρα πρέπει να ελευθερώνονται με την
close().
Το pipe() επιστρέφει 0 σε επιτυχία ή -1 σε αποτυχία.
6
7. Παράδειγμα 1: pipe1.c
#include <stdio.h>
main()
{
int fd[2], n;
char message[100];
pipe(fd);
write(fd[1], "This is a pipe message", 22);
n = read(fd[0], message, 100);
/* write the message to stdout */
write(1, message, n);
}
Η εκτέλεση του προγράμματος θα μας δώσει: This is a pipe message
7
8. Η function perror(const char * str)
Μερικές C functions, όταν συμβεί κάποιο λάθος,
θέτουν μία τιμή στη global var errno.
Η δουλειά της perror() είναι να εμφανίσει
- το αλφαριθμητικό str που της περάσαμε καθώς και
- το μήνυμα που αντιστοιχεί στην τιμή που έχει η errno.
Παράδειγμα
FILE * pFile = fopen ("unexist.ent","rb");
if (pFile==NULL)
perror ("The following error occurred");
else
fclose (pFile);
Τελικά θα εμφανιστεί: «The following error occurred: No such file or directory»
Η βασική χρησιμότητα του δικού μας μηνύματος είναι να μας βοηθάει να εντοπίσουμε το
σημείο του κώδικα που έγινε το λάθος.
8
9. Παράδειγμα 2: pipe2.c
#include <stdio.h>
char *line = "This is an IPC message, with pipe";
main()
{
int pid, fd[2], n;
char message[100];
if (pipe(fd) == -1)
{
perror("pipe");
exit(1);
}
pid = fork();
if ( pid == -1)
{
perror("fork");
exit(2);
}
9
10. if (pid == 0)
{ /* Child process is the writer */
close(fd[0]);
write(fd[1], line, strlen(line)+1);
close(fd[1]);
}
else
{ /* Parent process is the reader */
close(fd[1]);
n = read(fd[0], message, sizeof(message));
write(1, message, n); // write the message to the stdout
close(fd[0]);
}
}
Η εκτέλεση του προγράμματος θα μας δώσει:
This is an IPC message, with pipe
10
11. H function int dup2(int fildes, int fildes2);
Κάνει το fildes alias του fildes2
Παράδειγμα
Αν θέλουμε να κατευθύνουμε το standard output σε ένα αρχείο
int file = open("myfile.txt", O_APPEND | O_WRONLY);
if(file < 0) return 1; //Now we redirect standard output to the file using dup2
if(dup2(file,1) < 0) return 1;
//Now standard out has been redirected, we can write to the file
printf("This will be printed in myfile.txt“);
11
12. Παράδειγμα 3: pipe3.c
#include <stdio.h>
main()
{
int fd[2], pid;
char message[100];
if (pipe(fd) == -1)
{ /* Create a pipe */
perror("pipe");
exit(1);
}
if ((pid = fork()) == -1)
{ /* Fork a child */
perror("fork");
exit(2);
}
12
13. if (pid == 0)
{ /* Child process is the reader */
close(fd[1]);
dup2(fd[0],0); /* stdin becomes fd[0] */
close(fd[0]);
printf("I am the child…n");
scanf("%s",message);
printf("From parent: %sn", message);
scanf("%s", message);
printf("From parent: %sn", message);
scanf("%s", message);
printf("From parent: %sn", message);
exit(0);
}
else
{ /* Parent process is the writer */
close(fd[0]);
dup2(fd[1],1); /* stdout becomes fd[1] */
close(fd[1]);
printf("Hello my childn");
}
}
13
14. Παράδειγμα 4: pipe4.c
#include <stdio.h>
main()
{
int fd[2], pid;
char *argv[3];
if (pipe(fd) == -1)
{ /* Create a pipe */
perror("pipe");
exit(1);
}
if ((pid = fork()) == -1)
{ /* Fork a child */
perror("fork");
exit(2);
}
14
15. if (pid == 0)
{ /* Child process is the reader */
close(fd[1]); /* Close the writing side */
dup2(fd[0],0); /* stdin becomes fd[0] */
close(fd[0]); /* now, close the fd[0] */
execlp("wc", "wc" , NULL);
perror("execlp");
}
else
{ /* Parent process is the writer */
close(fd[0]); /* Close the reading side */
dup2(fd[1],1); /* stdout becomes fd[1] */
close(fd[1]); /* now, close the fd[1] */
argv[0] = "ls";
argv[1] = "-l";
argv[2] = NULL;
execvp("ls", argv);
perror("execvp");
}
}
15
16. Με τη χρήση των FIFO μπορούν να ανταλλάξουν δεδομένα και διεργασίες
που δεν έχουν «συγγενική» σχέση μεταξύ τους
Η κλήση συστήματος mkfifo() δημιουργεί έναν επώνυμο σωλήνα που έχει τις
ίδιες ιδιότητες με έναν ανώνυμο σωλήνα (half-duplex, fist in – first out),
με τη διαφορά ότι στην ουσία πρόκειται για ένα αρχείο στο δίσκο
int mkfifo(const char *path, mode_t mode);
16
17. Παράδειγμα 5: fifo1.c
main()
{
int fd, n;
char buff[100], msg[]="Text for FIFO";
unlink("FIFO"); /* remove, if exist */
if (mkfifo("FIFO", 0764) == -1)
{
perror("mkfifo");
exit(1);
}
if ((fd=open("FIFO", O_RDWR)) == -1)
{
perror("open");
exit(2);
}
n=write(fd,msg,strlen(msg));
if (read(fd, buff, n)==-1)
fprintf(stderr,"Can't read from Fifo.n");
else
printf("Read from FIFO: %sn", buff);
}
17
18. Παράδειγμα 6: receiver.c
int main()
{
int fd;
char buffer[100];
unlink("FIFO");
if (mkfifo("FIFO", 0755) == -1)
{
fprintf(stderr,"Receiver: Coudn't create fifo.n");
exit(2);
}
if ((fd = open("FIFO", O_RDWR)) == -1)
{
fprintf(stderr, "Receiver: fifo open failed.n");
exit(1);
}
18