read(...)
and write(...)
functions provide raw (unbuffered I/O to storage via file descriptors)#include <fcntl.h>
// read(...) returns the number of bytes read or -1 on error
// errno is also set upon on error
int read( int handle, void *buffer, size_t nbyte );
// write returns the number of bytes written or -1 on error
//errno is also set upon error
int write( int handle, void *buffer, size_t nbyte );
open(...)
ed in the appropriate modeSSIZE_MAX
, in POSIX >= 32767)buffer is a pointer to the memory location where the data will be copied to/from
The read(...)
function attempts to read nbytes
from the file associated with handle, and places the characters read into buffer.
write()
function attempts to write nbytes
from buffer to the file associated with handle.errno
should be displayed using the perror(...)
// The contents of the string pointed to by str are appended to the
// beginning of the errno message
void perror ( const char * str );
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile=fopen ("unexist.ent","rb");
if (pFile==NULL)
perror ("The following error occurred");
else
fclose (pFile);
return 0;
}
int i, buffsize, bytes;
char buff[buffsize];
...
for(i = 0; i < buffsize; i++){
bytes = read(STDIN_FILENO, &buff[i], sizeof(char));
...
}
//Example 1
int integer, bytes;
...
bytes = read(STDIN_FILENO, &integer, sizeof(int));
Example 2
typedef struct token_header {
....
} token_hdr_t;
token_hdr_t thp;
bytes = read(fd,&thp,sizeof(token_hdr_t));
read(...)
function is limmited by:
socket
)write(...)
function include:
open(...)
call ( O_RDONLY, O_WRONLY, ORDWR and O_APPEND)
#include <unistd.h>
int pipe(int filedes[2]);
fildes[0]
and fildes[1]
.center[]
fork()
:
fork()
:
.center[fd[0]
) and the child closes the write-end of the pipe (fd[1]
) to create a pipe from the parent to the child:.center[]
int main(void) {
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (pipe(fd) < 0)
perror("pipe error");
if ((pid = fork()) < 0) {
perror("fork error");
} else if (pid > 0) { /* parent */
close(fd[0]);
write(fd[1], "hello world\n", 12);
} else { /* child */
close(fd[1]);
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
}
exit(0);
}
dup(...)
and dup2(...)
allow for the manipulation of file descriptors.#include <unistd.h>
int dup(int filedes)
int dup2(int filedes, int filedes2);
dup2(...)
closes the entry filedes2
of the file descriptor table, and then copies the pointer of entry filedes
into filedes2
.dup2(...)
returns the value of the second parameter (fildes2
) upon success. A negative return value means that an error occured. errno
is also set on error.dup(...)
function duplicates the file descriptor, returning the lowest file descriptor available in the table. (i.e. the file descriptor returned by dup(...)
points to the same entry in the system file table.center[]
void make_trivial_ring(){
int fd[2];
pipe (fd);
dup2(fd[0], STDIN_FILENO);
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
}
void add_new_node(int *pid){
int fd[2];
pipe (fd);
*pid = fork();
if (*pid > 0) dup2(fd[1], STDOUT_FILENO);
else dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
}
.center[]
.center[]
dup2(fd[0],STDIN_FILENO);
.center[]
fd[0]
and fd[1]
.center[]
.center[]
int main(int argc, char *argv[ ]){
int i, childpid;
make_trivial_ring();
for (i = 1; i < atoi(argv[1]); i++){
add_new_node(&childpid);
if (childpid) break; }
fprintf(stderr,
"I'm %d ID = %d parent ID = %d\n",
i, (int)getpid(), (int)getppid());
sleep(5);
exit(0);
}
Note the way the ring grows, with the parent breaking out of the loop. We could just as easily do it the other way, but this way is more convenient.
/* written by ian a. mason @ une march '98 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int parse_args(int argc, char *argv[ ], int *np){
if ( (argc != 2) || ((*np = atoi (argv[1])) <= 0) ) {
fprintf (stderr, "Usage: %s nprocs\n", argv[0]);
return(-1); };
return(0);
}
...
int make_trivial_ring(){
int fd[2];
if (pipe (fd) == -1)
return(-1);
if ((dup2(fd[0], STDIN_FILENO) == -1) ||
(dup2(fd[1], STDOUT_FILENO) == -1))
return(-2);
if ((close(fd[0]) == -1) || (close(fd[1]) == -1))
return(-3);
return(0); }
int add_new_node(int *pid){
int fd[2];
if (pipe(fd) == -1)
return(-1);
if ((*pid = fork()) == -1)
return(-2);
if(*pid > 0 && dup2(fd[1], STDOUT_FILENO) < 0)
return(-3);
if (*pid == 0 && dup2(fd[0], STDIN_FILENO) < 0)
return(-4);
if ((close(fd[0]) == -1) || (close(fd[1]) == -1))
return(-5);
return(0);
}
int main(int argc, char *argv[ ]){
int i; /* number of this process (starting with 1) */
int childpid; /* indicates process should spawn another */
int nprocs; /* total number of processes in ring */
if(parse_args(argc,argv,&nprocs) < 0) exit(EXIT_FAILURE);
if(make_trivial_ring() < 0){
perror("Could not make trivial ring");
exit(EXIT_FAILURE); };
for (i = 1; i < nprocs; i++) {
if(add_new_node(&childpid) < 0){
perror("Could not add new node to ring");
exit(EXIT_FAILURE); };
if (childpid) break; };
/* ring process code */
fprintf(stderr, "node %d of %d\n", i, nprocs);
exit(EXIT_SUCCESS);
} /* end of main program here */