Pipe n n n Pipe is a halfduplex

  • Slides: 38
Download presentation

Pipe n n n Pipe is a half-duplex communication channel between processes that have

Pipe n n n Pipe is a half-duplex communication channel between processes that have parent-child relation. Pipe() opens a pipe for reading at one end, and writing at the other. After creating a pipe a process usually creates another copy by fork, so that they share the pipe. Usually the parent and the child will decide whether to read from or write to the pipe, and will close the other end that they do not need. 2

The 5 basic Syscalls for I/O 5. int open(char *path, int flags [ ,

The 5 basic Syscalls for I/O 5. int open(char *path, int flags [ , int mode ] ); (check man –s 2 open) int close(int fd); int read(int fd, char *buf, int size); int write(int fd, char *buf, int size); off_t lseek(int fd, off_t offset, int whence); n fd: file descriptor, a ressource handler for a file, represented as an int 1. 2. 3. 4. n 3

How it works ? foo. exe mozilla 0 x. FFFF stack a fd is

How it works ? foo. exe mozilla 0 x. FFFF stack a fd is an index in an OS table forbidden kernel … File descriptor tables heap fd = open(“/tmp/foo. txt“); 0 x 0000 push 0 x 010 F mov ax, 3 int 0 x 80 mov bx, ax sys_close(){…} sys_open(){…} interrupt table code process can not forge fds will check if foo. exe can access foo. txt 4

Standard Input, Output and Error n Now, every process in Unix starts out with

Standard Input, Output and Error n Now, every process in Unix starts out with three file descriptors predefined: q q q n You can read from standard input, using read(0, . . . ), and write to standard output using write(1, . . . ) or using two library calls q q n File descriptor 0 is standard input. File descriptor 1 is standard output. File descriptor 2 is standard error. printf Scanf So int fd = open(“/tmp/foo. txt”, O_RDONLY); should return 3 Use ls /proc/self/fd to see the devices/files they point to 5

Low-level File Access n n Open To create a new file descriptor we need

Low-level File Access n n Open To create a new file descriptor we need to used the open system call #include <fcntl. h> #include <sys/types. h> #include <sys/stat. h> int open(const char *path, int oflags); int open(const char *path, int oflags, mode_t mode); 6

n ofalgs Mode Description O-RDONLY Open for read-only O_WRONLY Open for write-only O_RDWR Open

n ofalgs Mode Description O-RDONLY Open for read-only O_WRONLY Open for write-only O_RDWR Open for reading and writing The call may also include a combination of the following optional modes in the oflags parameter q q q O_APPEND Place written data at the end of the file O_TRUNC Set the length of the file to zero, discarding exiting contents O_CREAT Creates the file, if necessary, with permissions given in mode 7

#include <fcntl. h> #include <stdio. h> #include <sys/stat. h> #include <sys/types. h> #include <unistd.

#include <fcntl. h> #include <stdio. h> #include <sys/stat. h> #include <sys/types. h> #include <unistd. h> int main (int argc, char* argv[]) { const char* const filename = argv[1]; int fd = open (filename, O_RDONLY); printf (“in process %d, file descriptor %d is open to %sn”, (int) getpid (), (int) fd, filename); while (1); return 0; } 8

Low-level File Access n Read #include <unistd. h> size_t read(int fildes, void *buf, size_t

Low-level File Access n Read #include <unistd. h> size_t read(int fildes, void *buf, size_t nbytes); n It returns the number of data bytes actually read, which my be less than the number requested n If a read call returns 0, it had nothing to read; it reached the end of the file n If a read call returns -1, an error occurs 9

Low-level File Access n write #include <unistd. h> size_t write(int fildes, const void *buf,

Low-level File Access n write #include <unistd. h> size_t write(int fildes, const void *buf, size_t nbytes); n n n The write system call arranges for the first nbytes from buf to be written to the file associated with the file descriptor fildes. It returns the number of bytes actually written This may be less than nbytes if there has been an error in the file descriptor, of if the underlying device driver is sensitive to block size If the function return 0, it means no data was written, if -1, there has been an error in the write call and the error will be specified in the errno global variable 10

Low-level File Access n close #include <unistd. h> int close(int fildes); n n We

Low-level File Access n close #include <unistd. h> int close(int fildes); n n We use to terminate the association between a file descriptor, fildes, and its file The file descriptor becomes available for reuse It returns 0 if successful and -1 on error It is important to check the return result from close since some file systems, particularly networked ones, may not report an error writing to a file until the file is closed 11

#include <stdio. h> #include <stdlib. h> #include <errno. h> #include <unistd. h> int main()

#include <stdio. h> #include <stdlib. h> #include <errno. h> #include <unistd. h> int main() { int pfds[2]; char buf[30]; if (pipe(pfds) == -1) { perror("pipe"); exit(1); } printf("writing to file descriptor #%dn", pfds[1]); write(pfds[1], "test", 5); printf("reading from file descriptor #%dn", pfds[0]); read(pfds[0], buf, 5); printf("read "%s"n", buf); } 12

#include <stdio. h> #include <stdlib. h> #include <sys/types. h> #include <unistd. h> int main()

#include <stdio. h> #include <stdlib. h> #include <sys/types. h> #include <unistd. h> int main() { int pfds[2]; char buf[30]; pipe(pfds); if (!fork()) { printf(" CHILD: writing to the pipen"); write(pfds[1], "test", 5); printf(" CHILD: exitingn"); exit(0); } else { printf("PARENT: reading from pipen"); read(pfds[0], buf, 5); printf("PARENT: read "%s"n", buf); wait(NULL); } } 13

// The 'consumer' program, pipe 4. c, that reads the data is much simpler.

// The 'consumer' program, pipe 4. c, that reads the data is much simpler. // The program works with next slide’s codes #include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main(int argc, char *argv[]) { int data_processed; char buffer[BUFSIZ + 1]; int file_descriptor; memset(buffer, '', sizeof(buffer)); sscanf(argv[1], "%d", &file_descriptor); data_processed = read(file_descriptor, buffer, BUFSIZ); printf("%d - read %d bytes: %sn", getpid(), data_processed, buffer); exit(EXIT_SUCCESS); } 14

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main()

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; pid_t fork_result; memset(buffer, '', sizeof(buffer)); if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } if (fork_result == 0) { sprintf(buffer, "%d", file_pipes[0]); (void)execl("pipe 4", buffer, (char *)0); exit(EXIT_FAILURE); } else { data_processed = write(file_pipes[1], some_data, strlen(some_data)); printf("%d - wrote %d bytesn", getpid(), data_processed); } } exit(EXIT_SUCCESS); } 15

pipes 與 dup 的關係 n dup (int file_descriptor) The dup always returns a new

pipes 與 dup 的關係 n dup (int file_descriptor) The dup always returns a new file descriptor using the lowest available number. 16

#include <stdio. h> #include <stdlib. h> #include <unistd. h> int main() { int pfds[2];

#include <stdio. h> #include <stdlib. h> #include <unistd. h> int main() { int pfds[2]; pipe(pfds); if (!fork()) { close(1); /* close normal stdout */ dup(pfds[1]); /* make stdout same as pfds[1] */ close(pfds[0]); /* we don't need this */ execlp("ls", NULL); } else { close(0); /* close normal stdin */ dup(pfds[0]); /* make stdin same as pfds[0] */ close(pfds[1]); /* we don't need this */ execlp("wc", "-l", NULL); } } 17

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main()

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; pid_t fork_result; if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } if (fork_result == (pid_t)0) { close(0); dup(file_pipes[0]); close(file_pipes[1]); execlp("od", "-c", (char *)0); exit(EXIT_FAILURE); } 18

else { close(file_pipes[0]); data_processed = write(file_pipes[1], some_data, strlen(some_data)); close(file_pipes[1]); printf("%d - wrote %d bytesn",

else { close(file_pipes[0]); data_processed = write(file_pipes[1], some_data, strlen(some_data)); close(file_pipes[1]); printf("%d - wrote %d bytesn", (int)getpid(), data_processed); } } exit(EXIT_SUCCESS); } 19

After the call to fork: When the program is rady to transfer data: 20

After the call to fork: When the program is rady to transfer data: 20

dup 2 () Using the dup 2 call, you can equate one file descriptor

dup 2 () Using the dup 2 call, you can equate one file descriptor with another. n n dup 2 (fd, STDIN_FILENO); 21

#include <stdio. h> #include <sys/types. h> #include <sys/wait. h> #include <unistd. h> int main

#include <stdio. h> #include <sys/types. h> #include <sys/wait. h> #include <unistd. h> int main () { int fds[2]; pid_t pid; /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */ pipe (fds); /* Fork a child process. */ pid = fork (); if (pid == (pid_t) 0) { /* This is the child process. Close our copy of the write end of the file descriptor. */ close (fds[1]); /* Connect the read end of the pipe to standard input. */ dup 2 (fds[0], STDIN_FILENO); /* Replace the child process with the “sort” program. */ execlp (“sort”, 0); } 22

else { /* This is the parent process. */ FILE* stream; /* Close our

else { /* This is the parent process. */ FILE* stream; /* Close our copy of the read end of the file descriptor. */ close (fds[0]); /* Convert the write file descriptor to a FILE object, and write to it. */ stream = fdopen (fds[1], “w”); fprintf (stream, “This is a test. n”); fprintf (stream, “Hello, world. n”); fprintf (stream, “My dog has fleas. n”); fprintf (stream, “This program is great. n”); fprintf (stream, “One fish, two fish. n”); fflush (stream); close (fds[1]); /* Wait for the child process to finish. */ waitpid (pid, NULL, 0); } return 0; } 23

FIFO n n n A FIFO is a named pipe, that is, a pipe

FIFO n n n A FIFO is a named pipe, that is, a pipe with a name in the file system. FIFO is a special kind of file. In fact it is simply a place where different processes (not necessarily have parent-child relation) can communicate. If O_NONBLOCK is specified, the open for reading returns immediately, but the open for write-only will have runtime error. 24

FIFO From inside a program, we can use two different calls. These are: 25

FIFO From inside a program, we can use two different calls. These are: 25

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <sys/types. h> #include <sys/stat.

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <sys/types. h> #include <sys/stat. h> int main() { int res = mkfifo("my_fifo", 0777); if (res == 0) printf("FIFO createdn"); exit(EXIT_SUCCESS); } $ ls –al my_fifo $cat < my_fifo & $ echo “abcdefg” > my_fifo $ cat my_fifo 26

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> #include <fcntl.

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> #include <fcntl. h> #include <sys/types. h> #include <sys/stat. h> #define FIFO_NAME "my_fifo" int main(int argc, char *argv[]) { int res; int open_mode = 0; int i; if (argc < 2) { fprintf(stderr, "Usage: %s <some combination of O_RDONLY O_WRONLY O_NONBLOCK>n", *argv); exit(EXIT_FAILURE); } // Assuming that the program passed the test, we now set the value of open_mode // from those arguments. 27

for(i = 1; i < argc; i++) { if (strncmp(*++argv, "O_RDONLY", 8) == 0)

for(i = 1; i < argc; i++) { if (strncmp(*++argv, "O_RDONLY", 8) == 0) open_mode |= O_RDONLY; if (strncmp(*argv, "O_WRONLY", 8) == 0) open_mode |= O_WRONLY; if (strncmp(*argv, "O_NONBLOCK", 10) == 0) open_mode |= O_NONBLOCK; } // We now check whether the FIFO exists and create it if necessary. // Then the FIFO is opened and output given to that effect while the program // catches forty winks. Last of all, the FIFO is closed. if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0777); if (res != 0) { fprintf(stderr, "Could not create fifo %sn", FIFO_NAME); exit(EXIT_FAILURE); } } 28

printf("Process %d opening FIFOn", getpid()); res = open(FIFO_NAME, open_mode); printf("Process %d result %dn", getpid(),

printf("Process %d opening FIFOn", getpid()); res = open(FIFO_NAME, open_mode); printf("Process %d result %dn", getpid(), res); sleep(5); if (res != -1) (void)close(res); printf("Process %d finishedn", getpid()); exit(EXIT_SUCCESS); } $. /fifo 2 O_RDONLY & $. /fifo 2 O_WRONLY $. /fifo 2 O_RDONLY O_NONBLOCK & $. /fifo 2 O_WRONLY 29

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> #include <fcntl.

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> #include <fcntl. h> #include <limits. h> #include <sys/types. h> #include <sys/stat. h> #define FIFO_NAME "/tmp/my_fifo" #define BUFFER_SIZE PIPE_BUF #define TEN_MEG (1024 * 10) int main() { int pipe_fd; int res; int open_mode = O_WRONLY; int bytes_sent = 0; char buffer[BUFFER_SIZE + 1]; if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0777); if (res != 0) { fprintf(stderr, "Could not create fifo %sn", FIFO_NAME); exit(EXIT_FAILURE); } } printf("Process %d opening FIFO O_WRONLYn", getpid()); pipe_fd = open(FIFO_NAME, open_mode); printf("Process %d result %dn", getpid(), pipe_fd); 30

if (pipe_fd != -1) { while(bytes_sent < TEN_MEG) { res = write(pipe_fd, buffer, BUFFER_SIZE);

if (pipe_fd != -1) { while(bytes_sent < TEN_MEG) { res = write(pipe_fd, buffer, BUFFER_SIZE); if (res == -1) { fprintf(stderr, "Write error on pipen"); exit(EXIT_FAILURE); } bytes_sent += res; } (void)close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finishedn", getpid()); exit(EXIT_SUCCESS); } 31

//fifo 4. c #include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string.

//fifo 4. c #include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> #include <fcntl. h> #include <limits. h> #include <sys/types. h> #include <sys/stat. h> #define FIFO_NAME "/tmp/my_fifo" #define BUFFER_SIZE PIPE_BUF int main() { int pipe_fd; int res; int open_mode = O_RDONLY; char buffer[BUFFER_SIZE + 1]; int bytes_read = 0; memset(buffer, '', sizeof(buffer)); printf("Process %d opening FIFO O_RDONLYn", getpid()); pipe_fd = open(FIFO_NAME, open_mode); printf("Process %d result %dn", getpid(), pipe_fd); 32

if (pipe_fd != -1) { do { res = read(pipe_fd, buffer, BUFFER_SIZE); bytes_read +=

if (pipe_fd != -1) { do { res = read(pipe_fd, buffer, BUFFER_SIZE); bytes_read += res; } while (res > 0); (void)close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finished, %d bytes readn", getpid(), bytes_read); exit(EXIT_SUCCESS); } $. /fifo 3 & $. Time. /fifo 4 33

popen and pclose n n n the simplest way of passing data between two

popen and pclose n n n the simplest way of passing data between two programs The popen function allows a program to invoke another program as a new process and either pass data to or receive data from it. When the process started with popen has finished, we can close the file stream associated with it using pclose. 34

35

35

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main()

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main() { FILE *read_fp; char buffer[BUFSIZ + 1]; int chars_read; memset(buffer, '', sizeof(buffer)); read_fp = popen("uname -a", "r"); if (read_fp != NULL) { chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); if (chars_read > 0) { printf("Output was: -n%sn", buffer); } pclose(read_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } 36

#include <unistd. h> #include <stdlib. h> #include <stdio. h> int main() { FILE *write_fp;

#include <unistd. h> #include <stdlib. h> #include <stdio. h> int main() { FILE *write_fp; char buffer[BUFSIZ + 1]; sprintf(buffer, "Once upon a time, there was. . . n"); write_fp = popen("od -c", "w"); if (write_fp != NULL) { fwrite(buffer, sizeof(char), strlen(buffer), write_fp); pclose(write_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } 37

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main()

#include <unistd. h> #include <stdlib. h> #include <stdio. h> #include <string. h> int main() { FILE *read_fp; char buffer[BUFSIZ + 1]; int chars_read; memset(buffer, '', sizeof(buffer)); read_fp = popen("ps -ax", "r"); if (read_fp != NULL) { chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); while (chars_read > 0) { buffer[chars_read - 1] = ''; printf("Reading: -n %sn", buffer); chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); } pclose(read_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } 38