Operating Systems Concept Assaignemtn 02
Operating Systems Concept Assaignemtn 02
FA12-BCE-012
FA12-BCE-040
The first integer in the array (element 0) is set up and opened for reading, while the
second integer (element 1) is set up and opened for writing. Visually speaking, the
output of fd1 becomes the input for fd0. Once again, all data traveling through the
pipe moves through the kernel.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
main()
{
int
fd[2];
pipe(fd);
.
.
Remember that an array name in C decays into a pointer to its first member.
Above, fd is equivalent to &fd[0]. Once we have established the pipeline, we then
fork our new child process:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
main()
{
int
pid_t
fd[2];
childpid;
pipe(fd);
If the parent wants to receive data from the child, it should close fd1, and the child
should close fd0. If the parent wants to send data to the child, it should close fd0, and
the child should close fd1. Since descriptors are shared between the parent and child,
we should always be sure to close the end of pipe we aren't concerned with. On a
technical note, the EOF will never be returned if the unnecessary ends of the pipe are
not explicitly closed.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
main()
{
int
pid_t
fd[2];
childpid;
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
}
else
{
}
.
.
As mentioned previously, once the pipeline has been established, the file descriptors
may be treated like descriptors to normal files.
/*****************************************************************************
Excerpt from "Linux Programmer's Guide - Chapter 6"
(C)opyright 1994-1995, Scott Burkett
*****************************************************************************
MODULE: pipe.c
*****************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int
pid_t
char
char
fd[2], nbytes;
childpid;
string[] = "Hello, world!\n";
readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string)+1));
exit(0);
}
else
{
rpcprog_clnt.c
rpcprog_svc.c
rpcprog_xdr.c
rpcprog.h
There is just one function on the client side of the simplified interface
rpc_call().
This function calls the procedure specified by prognum, versum, and procnum on the
host. The argument to be passed to the remote procedure is pointed to by
the in parameter, and inproc is the XDR filter to encode this argument.
The out parameter is an address where the result from the remote procedure is to be
placed. outproc is an XDR filter which will decode the result and place it at this
address.
The client blocks on rpc_call() until it receives a reply from the server. If the server
accepts, it returns RPC_SUCCESS with the value of zero. It will return a non-zero value if
the call was unsuccessful. This value can be cast to the type clnt_stat, an enumerated
type defined in the RPC include files (<rpc/rpc.h>) and interpreted by
the clnt_sperrno() function. This function returns a pointer to a standard RPC error
message corresponding to the error code. In the example, all "visible" transports listed
in /etc/netconfig are tried. Adjusting the number of retries requires use of the lower
levels of the RPC library. Multiple arguments and results are handled by collecting
them in structures.
The example changed to use the simplified interface, looks like
#include
#include
#include
#include
<stdio.h>
<utmp.h>
<rpc/rpc.h>
<rpcsvc/rusers.h>
exit(1);
The argument and result are passed as addresses. This is true for all functions
that are called remotely. If you pass NULL as a result of a function, then no reply is sent
to the client. It is assumed that there is no reply to send.
The result must exist in static data space because its value is accessed after the
actual procedure has exited. The RPC library function that builds the RPC reply
message accesses the result and sends the value back to the client.
Only a single argument is allowed. If there are multiple elements of data, they
should be wrapped inside a structure which can then be passed as a single entity.
The procedure is registered for each transport of the specified type. If the type
parameter is (char *)NULL, the procedure is registered for all transports specified
in NETPATH.
You can sometimes implement faster or more compact code than
can rpcgen. rpcgen handles the generic code-generation cases. The following program
is an example of a hand-coded registration routine. It registers a single procedure and
enters svc_run() to service requests.
#include <stdio.h>
#include <rpc/rpc.h>
#include <rpcsvc/rusers.h>
void *rusers();
main()
{
if(rpc_reg(RUSERSPROG, RUSERSVERS,
RUSERSPROC_NUM, rusers,
xdr_void, xdr_u_long,
"visible") == -1) {
fprintf(stderr, "Couldn't Register\n");
exit(1);
}
svc_run(); /* Never returns */
fprintf(stderr, "Error: svc_run returned!\n");
exit(1);
}