Lab Record
Lab Record
A. Environment Used 2
Editors in Linux 3
Compiling Using gcc 5
B. Threads 7
1. Dining Philosopher’s Problem using pthread 10
2. Banker’s Algorithm 14
C. Forks 19
D. Interprocess Communication 20
3. Expression Evaluation using Fork and Shared 29
Memory
4. IPC Using Pipes 32
5. IPC Using Message Queue 37
E. Socket Programming 41
6. Client-Server Communication using TCP 47
7. Client-Server Communication using UDP 52
F. MAC Protocols 57
8. 1-bit Sliding Window Protocol 60
9. Go-Back-N Sliding Window Protocol 68
10. Selective Repeat Protocol 78
11. SMTP using UDP 89
12. FTP using TCP 97
G. Virtual File System 105
13. Disk Usage Status Report 107
H. Remote Procedure Call 110
14. Finger Utility using RPC 114
Linux distributions have mainly been used as server operating systems, and have
risen to prominence in that area. Linux distributions are the cornerstone of the LAMP
server-software combination (Linux, Apache, MySQL, Perl/PHP/Python) which has
achieved popularity among developers, and which is one of the more common
platforms for website hosting. There are many Linux Distributions available these days
which consist of the Linux kernel and, usually, a set of libraries and utilities from the
GNU project, with graphics support from the X Window System. One can distinguish
between commercially backed distributions, such as Fedora (Red Hat), openSUSE
(Novell), Ubuntu (Canonical Ltd.), and Mandriva Linux and community distributions
such as Debian and Gentoo, though there are other distributions that are driven neither
by a corporation nor a community; perhaps most famously, Slackware.
Editors in Linux
Many editors are available inbuilt in Linux itself for the purpose of editing. One
of those may be used for programming too. Some of the common editors are gedit, vi,
vim, nano, kedit etc. All of them provide different options for editing. Here, we use vi
editor for coding purpose. The commands used in vi are:
vi <filename>
Exiting vi:
:q<return> - quit vi
Insert mode
Command mode
Replace mode
Execute mode
3 OS & Network Lab Record SCTCE
Visual mode
Command mode
- To copy a group of lines : enter number of lines to be copied and then press yy
Eg: 5yy
- To cut a group of lines : enter number of lines to be copied and then press cc
Eg: 5cc
- To delete a group of lines : enter number of lines to be copied and then press dd
Eg: 5dd
- To go backwards – press N
Insert Mode
Normally when we open a file in vi, it will be in command mode. Now to enter
text into the file, we need to be in Insert Mode. To switch from command to insert mode
simply press Insert key or ‘i’. This mode is used to manually edit the file.
While compiling using gcc, there are several options available. Generally,
compiling a file is done by entering a command at the terminal in the following syntax:
What the option –o<output file> does: Place output in file <output file>. This applies
regardless to whatever sort of output is being produced, whether it be an executable
file, an object file, an assembler file or preprocessed C code. Since only one output file
can be specified, it does not make sense to use -o when compiling more than one input
file, unless you are producing an executable file as output. If -o is not specified, the
What the option –c does: Compile or assemble the source files, but do not link. The
linking stage simply is not done. The ultimate output is in the form of an object file for
each source file.
To compile multiple files in gcc: Write the commands for compiling the individual
files in a shell script with .sh extension and run this script file. All the files will get
compiled.
For eg: to compile the files server.c, client.c, finger_clnt.c, finger_svc.c and
finger_xdr.c specify the following commands inside a shell script file say, compile.sh.
gcc -c client.c -o cl
To execute the compile.sh file, give the following command in command line
The POSIX standard defines an API for creating and manipulating threads.
Pthreads defines a set of programming C language types, functions and constants. It is
implemented with a header and a thread library. Programmers can use Pthreads to
create, manipulate and manage threads, as well as between threads using mutex.
Mutex variables are one of the primary means of implementing thread synchronization
and for protecting shared data when multiple writes occur. A mutex variable acts like a
"lock" protecting access to a shared data resource. The basic concept of a mutex as used
in Pthreads is that only one thread can lock (or own) a mutex variable at any given
7 OS & Network Lab Record SCTCE
time. Thus, even if several threads try to lock a mutex only one thread will be
successful. No other thread can own that mutex until the owning thread unlocks that
mutex. Threads must "take turns" accessing protected data.
Thread Creation
The pthread_create function creates a new thread. It is provided with the following:
2. A pointer to a thread attribute object. This object controls details of how the
thread interacts with the rest of the program. If you pass NULL as the thread
attribute, a thread will be created with the default thread attributes.
4. A thread argument value of type void*. Whatever you pass is simply passed as
the argument to the thread function when the thread begins executing.
Thread Joining
For successfully execution of all the created threads, it should be ensured that
main thread never finishes executing first before the threads created by it. One solution
is to force main to wait until the other threads are done. For this we need a function that
waits for a thread. That function is pthread_join, which takes two arguments: the thread
ID of the thread to wait for, and a pointer to a void* variable that will receive the
finished thread’s return value.
Problem Description
The arrays represent the philosophers and corresponding chopsticks for them.
Each element in the philosopher’s array corresponds to a thread and each element in the
chopstick’s array corresponds to a mutex variable.
pthread_exit(NULL)
1. Start.
6. Stop.
1. Start.
4. Start eating.
7. Finish eating.
8. Stop.
pthread_t phil[5];
pthread_mutex_t chopstick[5];
void* func(int i){
printf("\nPhilisopher %d is thinking",i);
pthread_mutex_lock(&chopstick[i]);
pthread_mutex_lock(&chopstick[(i+1)%5]);
printf("\nPhilosopher %d is eating..",i);
sleep(2);
pthread_mutex_unlock(&chopstick[i]);
pthread_mutex_unlock(&chopstick[(i+1)%5]);
printf("\nPhilosopher %d has finished eating..",i);
pthread_exit(NULL);}
int main(){
int i,k;
void *msg;
for(i=0;i<5;i++){
k=pthread_mutex_init(&chopstick[i],NULL);
if(k==-1){
printf("\nError in initializing..");
exit(1);}}
for(i=0;i<5;i++){
k=pthread_create(&phil[i],NULL,(void*)func,(int*)i);
if(k==-1){
printf("\nError in creating..");
exit(1);}}
for(i=0;i<5;i++){
k=pthread_join(phil[i],&msg);
if(k==-1){
printf("\nError in joining..");
exit(1);}}
for(i=0;i<5;i++){
k=pthread_mutex_destroy(&chopstick[i]);
if(k==-1){
printf("\nError in destroying..");
exit(1);}}
return 0;}
Problem Description
The main data structures used here are: Two dimensional Arrays
These arrays represent the allocated matrix, maximum matrix, available matrix
and need matrix.
Procedure Safety
1. Let work and finish be vectors of length m & n. Initialize work = Available &
Finish[i] = false for I = 0, 1,.…., (n-1).
Go to step 2.
4. If finish [i] = true for all I, the system is in safe state else unsafe state.
1. If Request [i] <= Need [i] go to step 2 otherwise raise an error since the process
exceeded its maximum claim.
2. If Request [i] <=Available go to step 3, otherwise P [i] must wait since the resources
are not available.
need matrix
7 4 3
1 2 2
6 0 0
0 1 1
4 3 1
System is in safe state....
A child process is created from the parent process using the command
child_pid = fork ()
Shared Memory
Its second parameter specifies the number of bytes in the segment. Because
segments are allocated using pages, the number of actually allocated bytes is rounded
up to an integral multiple of the page size. The third parameter is the bitwise or of flag
values that specify options to shmget. The flag values include these:
segment_id=shmget(shm_key,getpagesize(),IPC_CREAT|S_IRUSR|S_IWUSER);
To make the shared memory segment available, a process must use shmat,
“Shared Memory ATtach” Pass it the shared memory segment identifier SHMID
returned by shmget. The second argument is a pointer that specifies where in your
process’s address space you want to map the shared memory; if you specify NULL,
Linux will choose an available address .The third argument is a flag, which can include
the following:
SHM_RND indicates that the address specified for the second parameter
should be rounded down to a multiple of the page size. If you don’t specify
this flag, you must page-align the second argument to shmat yourself.
SHM_RDONLY indicates that the segment will be only read, not written.
The shmctl (“SHared Memory ConTroL”) call returns information about a shared
memory segment and can modify it. The first parameter is a shared memory segment
identifier. To obtain information about a shared memory segment, pass IPC_STAT as
the second argument and a pointer to a struct shmid_ds. To remove a segment, pass
IPC_RMID as the second argument, and pass NULL as the third argument. The
segment is removed when the last process that has attached it finally detaches it. Each
shared memory segment should be explicitly deallocated using shmctl when you’re
finished with it, to avoid violating the system wide limit on the total number of shared
memory segments.
PIPES
% ls | less
access () :
The function checks whether the calling process can access the file pathname. The
mode specifies the accessibility check(s) to be performed, and is either the value
F_OK, or a mask consisting of the bitwise OR of one or more of R_OK, W_OK, and
X_OK. F_OK tests for the existence of the file.
open () :
Given a pathname for a file, open () returns a file descriptor, a small, non-negative
integer for use in subsequent system calls. The argument flags must include one of the
following access modes: O_RDONLY, O_WRONLY, or O_RDWR. This requests the file
to open in read-only, write-only, or read/write, respectively.
read () :
write () :
The function writes up to count bytes from the buffer pointed buf to the file referred to
by the file descriptor fd.
Message Queue
Message queue can be used for inter process communication between related or
unrelated process on a given host. Message queues are identified by a message queue
identifier. Any process with adequate privileges can place a message onto a given
queue, and any process with adequate privileges can read a message from a given
queue. There is no requirement that some process be waiting for a message to arrive on
queue before some process writes a message to that queue.
The return value is an integer identifier that is used in the other three msg functions to
refer to this queue, based on the specified key. oflag is a combination of the read-write
permission values. This can be bitwise-ORed with either IPC_CREAT or
IPC_CREAT|IPC_EXCL.
Once a message queue is opened by msgget, we put a message onto the queue
using msgsnd.
int msgsnd (int msgid, const void *ptr, size_t length, int flag)
struct msgbuf
};
The message type must be greater than 0, since non positive message types are
used as a special indicator to the msgrcv function.
The length argument to msgsnd specifies the length of the message in bytes. This
is the length of the user-defined data that follows the long integer message type. The
length can be 0.
The flag argument can be either 0 or IPC_NOWAIT. This flag makes the call to
msgsnd nonblocking: the function returns immediately if no room is available for the
new message.
length specifies the size of the data portion of the buffer pointed to by ptr. This is the
maximum amount of data that is returned by the function. This length excludes the
long integer type field.
If type is 0, the first message on the queue is returned. Since each message
queue is maintained as a FIFO list, a type of 0 specifies that the oldest
message on the queue is to be returned.
If type is greater than 0, the first message whose type equals ‘type’ is
returned.
If type is less than 0, the first message with the lowest type that is less than or
equal to the absolute value of the ‘type’ argument is returned.
The flag argument specifies what to do if a message of the requested type is not on the
queue. If the IPC_NOWAIT bit is set and no message is available, the msgrcv function
returns immediately with an error of ENOMSG.
In the cmd field, we use IPC_RMID which removes the message queue specified by
msgid from the system. Any messages currently on the queue are discarded. The third
argument is ignored for this operation.
Socket Stream styles guarantee delivery of all packets in the order they were
sent. If packets are lost or reordered by problems in the network, the receiver
automatically requests their retransmission from the sender. A connection-
style socket is like a telephone call: The addresses of the sender and receiver
are fixed at the beginning of the communication when the connection is
established.
Problem Description
shmget():
shmat ():
fork ():
Syntax: pid_t id
id = fork();
1. Start
6. Compute a*b
9. Compute c*d
10. Computed value of c*d is obtained from memory and added it to a*b in child
process.
11. Stop
Problem Description
access() :
open() :
read() :
write() :
Sender
1. Start
Client
8. Stop
Sender
#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
main()
{
char writepipe[] = "pipe1";
char readpipe[] = "pipe2";
int err;
char str1[50], str2[50];
int f1,f2;
if(access(writepipe,F_OK)== -1){
err = mkfifo(writepipe,0777);
if(err==-1){
printf("Error !!");
exit(1);}}
if(access(readpipe,F_OK)== -1){
err = mkfifo(readpipe,0777);
if(err==-1){
printf("Error !!");
exit(1);}}
f1 = open(writepipe,O_WRONLY);
if(f1==-1)
{
close(f1);
close(f2);
return(0);
}
Receiver
hello
hwru
Problem Description
struct name{
long int msgtype; /*Message Type*/
char buf[100]; /*Message Text*/
};
Functions used here are:
msgget() :
msgsnd() :
Syntax: int msgsnd(int msqid, const void *msgp, size_t msgsz,int msgflg)
msgrcv() :
Syntax: int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msgctl() :
Syntax: k=msgctl(id,IPC_RMID,0)
Sender
Receiver
9. Stop
#include<sys/msg.h>
struct name
{
long int msgtype;
char buf[100];
};
int main()
{
struct name rcv;
int msgid,i,len,j=0;
char temp[100][100];
printf("The received data is : ");
while(1)
{
strcpy(rcv.buf,"\0");
strcpy(temp[j],"\0");
msgid=msgget((key_t)2345,0666|IPC_CREAT);
if(msgid==-1)
{
printf("\nError in creating..");
}
rcv.msgtype=1;
msgrcv(msgid,(void*)&rcv,100,0,0);
if(strcmp(rcv.buf,"quit")==0)
break;
printf("%s",rcv.buf);
len=strlen(rcv.buf)-1;
for(i=len;i>0;i--)
temp[j][i]=rcv.buf[i];
j++;
}
for(i=0;i<j;i++)
{
strcpy(rcv.buf,temp[i]);
msgsnd(msgid,(void*)&rcv,100,0);
}
if(i==j)
{
strcpy(rcv.buf,"quit");
msgsnd(msgid,(void*)&rcv,100,0);
}
msgctl(msgid,IPC_RMID,0);
return(0);
}
#include<sys/msg.h>
struct name
{
long int msgtype;
char buf[100];
};
int main()
{
struct name snd;
int msgid;
printf("\nEnter the message to be send : ");
while(1)
{
msgid=msgget((key_t)2345,0666|IPC_CREAT);
if(msgid==-1)
{
printf("\nError in creating..");
}
snd.msgtype=1;
scanf("%s",snd.buf);
msgsnd(msgid,(void*)&snd,100,0);
if(strcmp(snd.buf,"quit")==0)
break;
strcpy(snd.buf,"\0");
}
while(1)
{
msgrcv(msgid,(void*)&snd,100,0,0);
if(strcmp(snd.buf,"quit")==0)
break;
printf("%s",snd.buf);
}
msgctl(msgid,IPC_RMID,0);
return(0);
}
Receiver
hello
hwru
Stream (SOCK_STREAM):
Datagram (SOCK_DGRAM):
A connectionless client illustrates the socket APIs that are written for User Datagram
Protocol (UDP).
socket ()
This function gives a socket descriptor that can be used in later system
calls.
protocol-> 0
bind ()
syntax: int bind (int fd, struct sockaddr *my_addr, int addrlen)
syntax: int connect (int fd, struct sockaddr* serv_addr, int addrlen)
listen ()
accept ()
send (): This function is used to send data over stream sockets. It returns
the number of bytes sent out.
flags-> 0
recv ()
This function receives the data send over the stream sockets. It returns the
number of bytes read into the buffer.
syntax: int recv (int fd, void *buf, int len,unsigned int flags)
flags-> set to 0
sendto ()
This function serves the same purpose as send () function except that it is
used for datagram sockets. It also returns the number of bytes sent out.
syntax: int sendto (int fd, const void *msg, int len, unsigned int flags, const
struct sockaddr *to, int tolen)
flags-> 0
recvfrom ()
This function serves the same purpose as recv () function except that it is
used for datagram sockets. It also returns the number of bytes received.
syntax: int sendto (int fd, const void *buf, int len, unsigned int flags, const
struct sockaddr *from, int fromlen)
flags-> set to 0
close()
Problem Description
struct sockaddr:
This structure holds socket address information for many types of sockets:
struct sockaddr
};
sa_family can be a variety of things, but it'll be AF_INET for everything we do in this
document. sa_data contains a destination address and port number for the socket.
};
This structure makes it easy to reference elements of the socket address. Note that
sin_zero (which is included to pad the structure to the length of a struct sockaddr)
should be set to all zeros with the function memset. Finally, the sin_port and sin_addr
must be in Network Byte Order!
System calls that allow to access the network functionality of a Unix box are as given
below. When you call one of these functions, the kernel takes over and does all the
work for you automatically.
Server Side:
Client Side:
TCP Server
1. Create a socket
4. Accept connections.
5. Receive data from client and reverse it, send it back to client.
TCP Client
#include"sys/socket.h"
#include"netinet/in.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int main(){
char buf[100];
int k;
int sock_desc;
struct sockaddr_in client;
memset(&client,0,sizeof(client));
sock_desc=socket(AF_INET,SOCK_STREAM,0);
if(sock_desc==-1){
printf("Error in socket creation");
exit(1);
}
client.sin_family=AF_INET;
client.sin_addr.s_addr=INADDR_ANY;
client.sin_port=3001;
k=connect(sock_desc,(struct sockaddr*)&client,sizeof(client));
if(k==-1){
printf("Error in connecting to server");
exit(1);
}
printf("\nEnter data to be send : ");
gets(buf);
k=send(sock_desc,buf,100,0);
if(k==-1){
printf("Error in sending");
exit(1);
}
close(sock_desc);
exit(0);
return 0;
}
Server
#include"sys/socket.h"
#include"netinet/in.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int main(){
char buf[100];
int k;
socklen_t len;
int sock_desc,temp_sock_desc;
struct sockaddr_in server,client;
sock_desc=socket(AF_INET,SOCK_STREAM,0);
if(sock_desc==-1){
printf("Error in socket creation");
exit(1);
}
server.sin_family=AF_INET;
server.sin_addr.s_addr=inet_addr("127.0.0.1");
server.sin_port=3001;
k=bind(sock_desc,(struct sockaddr*)&server,sizeof(server));
if(k==-1){
printf("Error in binding");
exit(1);
}
k=listen(sock_desc,20);
if(k==-1){
printf("Error in listening");
exit(1);
}
len=sizeof(client);
temp_sock_desc=accept(sock_desc,(struct sockaddr*)&client,&len);
if(temp_sock_desc==-1){
printf("Error in temporary socket creation");
exit(1);
}
k=recv(temp_sock_desc,buf,100,0);
if(k==-1){
printf("Error in receiving");
exit(1);
}
printf("Message got from client is : %s",buf);
close(temp_sock_desc);
exit(0);
return 0;
}
Server
Received:how are you
Problem Description
struct sockaddr:
This structure holds socket address information for many types of sockets:
struct sockaddr
};
sa_family can be a variety of things, but it'll be AF_INET for everything we do in this
document. sa_data contains a destination address and port number for the socket. To
deal with struct sockaddr, programmers created a parallel structure:
};
This structure makes it easy to reference elements of the socket address. Note
that sin_zero (which is included to pad the structure to the length of a struct sockaddr)
should be set to all zeros with the function memset. Finally, the sin_port and sin_addr
must be in Network Byte Order!
System calls that allow to access the network functionality of a Unix box are as given
below. When you call one of these functions, the kernel takes over and does all the work
for you automatically.
UDP Server
6. Display message
UDP Client
#include"sys/socket.h"
#include"sys/types.h"
#include"arpa/inet.h"
#include"netdb.h"
#include"unistd.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int main(){
socklen_t len;
char buf[100];
int sock_desc;
int k;
struct sockaddr_in client;
memset(&client,0,sizeof(client));
sock_desc=socket(AF_INET,SOCK_DGRAM,0);
if(sock_desc==-1){
printf("Error in creating socket");
exit(1);
}
client.sin_family=AF_INET;
client.sin_addr.s_addr=INADDR_ANY;
client.sin_port=3000;
k=bind(sock_desc,(struct sockaddr*)&client,sizeof(client));
if(k==-1){
printf("\nError in binding socket");
exit(1);
}
while(1){
len=sizeof(client);
k=recvfrom(sock_desc,buf,100,0,(struct sockadddr*)&client,&len);
if(k==-1){
printf("\nError in receiving pkt");
exit(1);
}
if((strcmp(buf,"end")==0)){
printf("End of transmission from server");
break;
}
printf("\n%s\n",buf);
}
close(sock_desc);
exit(0);
Server
#include"sys/socket.h"
#include"string.h"
#include"stdio.h"
#include"stdlib.h"
int main(){
char buf[100];
int i=1,k;
int sock_desc;
struct sockaddr_in server;
memset(&server,0,sizeof(server));
sock_desc=socket(AF_INET,SOCK_DGRAM,0);
if(sock_desc==-1){
printf("Error in creating socket");
exit(1);}
server.sin_family=AF_INET;
server.sin_addr.s_addr=inet_addr("127.0.0.1");
server.sin_port=3000;
while(1){
sprintf(buf,"Data Pkt %d",i);
k=sendto(sock_desc,buf,100,0,(struct sockaddr *)&server,sizeof(server));
if(k==-1){
printf("\nError in sending data pkts");
exit(1);}
sleep(1);
if(i>=5){
strcpy(buf,"end");
k=sendto(sock_desc,buf,100,0,(struct sockaddr
*)&server,sizeof(server));
break;
}
i++;
}
close(sock_desc);
exit(0);
return 0;
}
Server
Received: how are you
The Media Access Control (MAC) data communication protocol sub-layer , also
known as the medium Access Control, is a part of the data link layer specified in the
seven layer OSI model (layer 2) . It provides addressing and channel access control
mechanisms that make it possible for several terminal or network nodes to
communicate within a multipoint network (LAN) or Metropolitan Area Network
(MAN). AMAC protocol is not required in full-duplex point –to- point communication.
In single channel point –to- point communications full-duplex can be emulated. This
emulation can be considered a MAC layer.
The MAC sub-layer acts as an interface between the Logical Link Control
Sublayer and the network’s physical layer. The MAC layer provides an addressing
mechanism called physical address or MAC address. This is a unique serial number
assigned to each network adapter, making it possible to deliver data packets to a
destination within a subnetwork, i.e a physical network without routers, for example an
Ethernet network. Media access control is often used as a synonym to multiple access
protocol, since the MAC Sublayer provides the protocol and control mechanisms that
are required for a certain channel access method. This makes it possible for several
stations connected to the same physical medium to share it. Example of shared physical
medium are bus networks, ring networks, hub networks, wireless networks and half
duplex point-to–point links.
In the simplex, stop and wait protocols, data frames were transmitted in one
direction only. In most practical solutions, there is a need for transmitting data in both
directions. One way of achieving full-duplex data transmission is to have to separate
communication channels and use one for simplex data traffic. If this is done, we have
two separate physical circuits, each with a “forward: channel (for data) and a “reverse”
channel (for acknowledgments). In both case the bandwidth of the reverse channel is
almost wasted. A better idea is to use same circuit for data in both directions. In this
model data frames from A to B are intermixed with the acknowledgment frames A to B.
By looking at the field in the header of and incoming frame, the receiver can tell
whether the frame is data or acknowledgment. When a data from arrives, instead of
immediately sending a separate control frame, the receiver retains itself and waits until
the network layer passes it the next packet. The acknowledgment is attached to the
outgoing data frame. The technique of temporarily delaying outgoing
acknowledgments so that they can be hooked onto the next outgoing data frame is
known as piggybacking. The principal advantage of using piggybacking over having
distinct acknowledgment frames is a better use of the available channel bandwidth.
Bidirectional protocols that belong to a class called sliding window protocols. They
differ among themselves in terms of efficiency, complexity, and buffer requirements.
All sliding window protocols, each outbound frame contains a sequence number
ranging from 0 up to some maximum. The essence of all sliding window protocols is
that at any instant of time, the sender maintains a set of sequence numbers
corresponding frames it is permitted to send. These frames are said to fall within the
sending window, the receiver also maintains a receiving window corresponding to the
set of frames it is permitted to accept.
Two basic approaches are available for dealing with errors in the presence of
pipelining. One way, called go back N , is for the receiver simply to discard all
subsequent frames, sending no acknowledgments for the discarded frames. In other
words, the data link layer refuses to accept any frame except the next one it must give to
the network layer.
In this protocol, both the sender and receiver maintain a window of acceptable
sequence numbers. The sender’s window size starts out at 0 and grows to some
predefined maximum. The receiver’s window, in contrast, is always fixed in size and
equal to maximum. The receiver has a buffer reserved for each sequence number within
its fixed window. Whenever a frame arrives, its sequence number is checked by the
function between to see if falls within the window. If so and if it has not already been
received , it is accepted and stored. This action is taken without regard to whether or
not it contains the next packet expected by the network layer.
Problem Description
Develop a program to simulate 1-bit sliding window protocol. The sender sends
frame to the receiver. Since the size of the sliding window is only one bit, the sender
sends one frame and waits for the acknowledgment from the receiver for it. Unless the
acknowledgment is received, the sender cannot send more frames. For simulation
purpose, any one packet is supposed to be lost for the first time. Then client sends a
RETRANSMIT request along with the current packet number. On receiving this, the
server retransmits the lost packet.
Client
Server
Server
1. Start.
11. Stop.
Client
1. Start.
4. Accept the details from the server (total packets, total frames).
5. Initialize the receive buffer with the expected frame and packets.
61 OS & Network Lab Record SCTCE
6. Accept the frame and check for its validity.
10. Stop.
Code
Client
#include"sys/socket.h"
#include"netinet/in.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int main(int argc, char* argv[])
{
char buf[100],id[2];
int k,i=1,flag=0,num,pid;
int sock_desc;
struct sockaddr_in client;
memset(&client,0,sizeof(client));
sock_desc=socket(AF_INET,SOCK_STREAM,0);
if(sock_desc==-1)
{
printf("\nError in socket creation");
exit(1);
}
client.sin_family=AF_INET;
client.sin_addr.s_addr=inet_addr("127.0.0.1");
client.sin_port=atoi(argv[1]);
k=connect(sock_desc,(struct sockaddr*)&client,sizeof(client));
if(k==-1)
{
printf("\nError in connecting to server");
exit(1);
}
while(1)
{
if(flag==0)
{
printf("\nEnter the next packet number : ");
62 OS & Network Lab Record SCTCE
scanf("%d",&i);
}
else
i++;
if(i>9)
break;
printf("\nEnter data packet %d to be send : ",i);
id[0]=i;
id[1]='\0';
scanf("%s",buf);
k=send(sock_desc,id,sizeof(id),0);
if(k==-1)
{
printf("\nError in sending..");
exit(1);
}
k=recv(sock_desc,id,sizeof(id),0);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
}
if(id[0]=='~')
{
k=send(sock_desc,buf,sizeof(buf),0);
if(k==-1)
{
printf("\nError in sending");
exit(1);
}
sleep(2);
strcpy(buf,"\0");
k=recv(sock_desc,buf,sizeof(buf),0);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
}
printf("%s by the server\n\t",buf);
}
else
{
num=(int)id[0];
k=recv(sock_desc,id,sizeof(id),0);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
}
pid=(int)id[0];
k=recv(sock_desc,buf,sizeof(buf),0);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
Server
#include"sys/socket.h"
#include"netinet/in.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
memset(&server,0,sizeof(server));
memset(&client,0,sizeof(client));
sock_desc=socket(AF_INET,SOCK_STREAM,0);
if(sock_desc==-1)
{
printf("Error in socket creation");
exit(1);
}
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
server.sin_port=atoi(argv[1]);
k=bind(sock_desc,(struct sockaddr*)&server,sizeof(server));
if(k==-1)
{
printf("Error in binding");
k=listen(sock_desc,5);
if(k==-1)
{
printf("Error in listening");
exit(1);
}
len=sizeof(client);
temp_sock_desc=accept(sock_desc,(struct sockaddr*)&client,&len);
if(temp_sock_desc==-1)
{
printf("\nError in temporary socket creation");
exit(1);
}
printf("\n\nMessage got from client is : \n\t");
while(1)
{
k=recv(temp_sock_desc,id,sizeof(id),0);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
}
old = num;
num = (int)id[0];
if((num-old)==1)
{
id[0]='~';
id[1]='\0';
k=send(temp_sock_desc,id,sizeof(id),0);
if(k==-1)
{
printf("Error in sending\n");
exit(1);
}
k=recv(temp_sock_desc,buf,sizeof(buf),0);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
}
if(strcmp(buf,"END")==0)
break;
id[0]=num+48;
id[1]='\0';
printf("Data packet %d: %s\n\t",num,buf);
strcpy(buf,"\0");
strcpy(buf,"Data packet ");
strcat(buf,id);
strcat(buf," acknowledged");
printf("Acknowledging reception of data packet %s to the
client..\n\n\t",id);
k=send(temp_sock_desc,buf,sizeof(buf),0);
client
Socket created successfully...
Starting up...
Binding completed successfully. Waiting for connection..
Recieved a request from client. Sending packets one by one...
Packet Sent: 1
Packet Sent: 2
Packet Sent: 3
** Received a RETRANSMIT packet. Resending last packet...
Packet Sent: 3
Packet Sent: 4
Packet Sent: 5
Sending Complete. Sockets closed. Exiting...
Problem Description
Client
Server
WindowStart and WindowEnd are used to store the starting and ending of
window.
1. Start
2. Establish connection
11. Check for the acknowledgment of each packet and repeat the process from the
12. Increment the frame count and repeat steps 7 to 12 until all packets are
transmitted.
14. Stop.
1. Start.
4. Accept the details from the server (total packets, total frames)
7. Check the validity of the packet and construct the acknowledgment frame depending
on the validity. (Here the acknowledgment is accepted from the users)
9. Increment the frame count and repeat steps 5-9 until all packets are received.
11. Stop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
int main() {
int sockfd, newSockFd, size, firstTime = 1, currentPacket, wait = 3;
char data[100], digit[2];
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) {
printf("Error in socket creation...");
}
else {
printf("\nSocket Created...");
}
client.sin_family = AF_INET;
client.sin_port = PORT;
client.sin_addr.s_addr = inet_addr("127.0.0.1");
printf("\nStarting up...");
size = sizeof(client);
printf("\nEstablishing Connection...");
if(connect(sockfd, (struct sockaddr *)&client, size) == -1) {
printf("\nError in connecting to server...");
/*********************************/
/* SLIDING WINDOW GO-BACK SERVER */
/*********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <fcntl.h>
int main()
{
int sockfd, newSockFd, size, windowStart = 1, windowCurrent = 1,
windowEnd = 4, oldWindowStart, flag;
char buffer[100];
socklen_t len;
[root@Linux smtp]#./selrejs
[root@Linux smtp]#./selrejc
Client
Socket Created...
Starting up...
Establishing Connection...
Connection Established!
Got packet: 1
Got packet: 2
Got packet: 3
*** Simulation: Packet data corrupted or incomplete.
*** Sending RETRANSMIT for packet 1.
Got packet: 1
*** Packet Accepted -> Sending ACK
Got packet: 2
Got packet: 3
Got packet: 4
*** Packet Accepted -> Sending ACK
Got packet: 5
Got packet: 6
Got packet: 7
*** Packet Accepted -> Sending ACK
Got packet: 8
Got packet: 9
All packets recieved... Exiting.
76 OS & Network Lab Record SCTCE
Server
Socket created successfully...
Starting up...
Binding completed successfully. Waiting for connection..
Recieved a request from client. Sending packets one by one...
Packet Sent: 1
**2||4**
Packet Sent: 2
**3||4**
Packet Sent: 3
**4||4**
**4||4**
** Received a RETRANSMIT packet. Resending packet no. 1...
Packet Sent: 2
**3||4**
** Recieved ACK 1. Moving window boundary.
Packet Sent: 3
**4||5**
Packet Sent: 4
**5||5**
**5||5**
** Recieved ACK 4. Moving window boundary.
Packet Sent: 5
**6||8**
Packet Sent: 6
**7||8**
Packet Sent: 7
**8||8**
**8||8**
** Recieved ACK 7. Moving window boundary.
Packet Sent: 8
**9||11**
Packet Sent: 9
**10||11**
Sending Complete. Sockets closed. Exiting...
Problem Description
Client
Server
WindowStart and WindowEnd are used to store the starting and ending of
window.
Server
1. Start.
3. Accept the window size from the client (should be <= 40)
11. Check for the acknowledgment of each packet and repeat the process from the
packet for which the first negative acknowledgment is received.
12. Increment the frame count and repeat steps 7 to 12 until all packets are transmitted.
14. Stop.
1. Start.
4. Accept the details from the server (total packets, total frames)
7. Check the validity of the packet and construct the acknowledgment frame depending
on the validity. (Here the acknowledgment is accepted from the users )
9. Increment the frame count and repeat steps 5-9 until all packets are received.
11. Stop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 3599
int main()
{
int sockfd, newSockFd, size, firstTime = 1, currentPacket, wait = 3;
char data[100], digit[2];
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
printf("Error in socket creation...");
}
else
{
printf("\nSocket Created...");
}
client.sin_family = AF_INET;
client.sin_port = PORT;
client.sin_addr.s_addr = inet_addr("127.0.0.1");
printf("\nStarting up...");
size = sizeof(client);
printf("\nEstablishing Connection...");
if(connect(sockfd, (struct sockaddr *)&client, size) == -1)
/****************************/
/* SELECTIVE REJECT SERVER */
/****************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <fcntl.h>
int main() {
memset(&server, 0, sizeof(server));
memset(&client, 0, sizeof(client));
server.sin_family = AF_INET;
server.sin_port = PORT;
server.sin_addr.s_addr = INADDR_ANY;
printf("\nStarting up...");
len = sizeof(client);
memset(&buffer, 0, sizeof(buffer));
if(recv(newSockFd, buffer, 100, 0) == -1) {
printf("\n Recieve Error! Exiting...");
exit(1);
}
sleep(1);
} while(windowCurrent != 10);
}
else {
printf("\nError in listening...");
exit(1);
}
close(sockfd);
close(newSockFd);
printf("\nSending Complete. Sockets closed. Exiting...\n");
return(0);
}
[root@Linux smtp]#./selrejs
[root@Linux smtp]#./selrejc
Server
Socket created successfully...
Starting up...
Binding completed successfully. Waiting for connection..
Recieved a request from client. Sending packets one by one...
Packet Sent: 1
**2||4**
Packet Sent: 2
**3||4**
Packet Sent: 3
**4||4**
**4||4**
** Received a RETRANSMIT packet. Resending packet no. 3...
**4||4**
** Recieved ACK 3. Moving window boundary.
Packet Sent: 4
**5||7**
Packet Sent: 5
**6||7**
Packet Sent: 6
**7||7**
**7||7**
** Recieved ACK 6. Moving window boundary.
Packet Sent: 7
**8||10**
Packet Sent: 8
**9||10**
Packet Sent: 9
87 OS & Network Lab Record SCTCE
**10||10**
Sending Complete. Sockets closed. Exiting...
Client
Socket Created...
Starting up...
Establishing Connection...
Connection Established!
Got packet: 1
Got packet: 2
Got packet: 3
*** Simulation: Packet data corrupted or incomplete.
*** Sending RETRANSMIT.
Got packet: 3
*** Packet Accepted -> Sending ACK
Got packet: 4
Got packet: 5
Got packet: 6
*** Packet Accepted -> Sending ACK
Got packet: 7
Got packet: 8
Got packet: 9
*** Packet Accepted -> Sending ACK
All packets recieved... Exiting.
Problem Description
Develop a program to simulate SMTP using UDP connection. The input to the
program from the client side is the sender’s and receiver’s email id, which is of the form
[email protected]. The content of the mail is also accepted from the user. The server
validates the domain and the URL from which the mail is sent and displays the content
of the mail.
Client Side
1. Start
2. Create Socket
4. Get ‘Helo’ from user and send to server via the socket
5. Get other details such as destination email address, from email address and
message body from the client and send to server via the socket
7. Stop
Server Side
1. Start
2. Create Socket
8. Stop
90 OS & Network Lab Record SCTCE
Code
Smtpclient
#include"sys/socket.h"
#include"netinet/in.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int main()
{
char buf[100];
int k;
int sock_desc;
struct sockaddr_in client;
memset(&client,0,sizeof(client));
sock_desc=socket(AF_INET,SOCK_DGRAM,0);
if(sock_desc==-1)
{
printf("\nError in socket creation");
exit(1);
}
client.sin_family=AF_INET;
client.sin_addr.s_addr=inet_addr("127.0.0.1");
client.sin_port=3500;
printf("\nMAIL TO : ");
gets(buf);
k=sendto(sock_desc,buf,sizeof(buf),0,(struct
sockaddr*)&client,sizeof(client));
if(k==-1)
{
printf("\nError in sending");
strcpy(buf,"\0");
printf("\nSUBJECT : ");
gets(buf);
k=sendto(sock_desc,buf,sizeof(buf),0,(struct
sockaddr*)&client,sizeof(client));
if(k==-1)
{
printf("\nError in sending");
exit(1);
}
strcpy(buf,"\0");
printf("\nMSG BODY : ");
while(strcmp(buf,".")!=0)
{
strcpy(buf,"\0");
gets(buf);
k=sendto(sock_desc,buf,sizeof(buf),0,(struct
sockaddr*)&client,sizeof(client));
if(k==-1)
{
printf("\nError in sending");
exit(1);
} }
close(sock_desc);
#include"sys/socket.h"
#include"netinet/in.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int main()
{
char buf[100],domain[20],snd[25];
int k,i=0,j,m=0;
socklen_t len;
int sock_desc,temp_sock_desc;
struct sockaddr_in server,client;
memset(&server,0,sizeof(server));
memset(&client,0,sizeof(client));
sock_desc=socket(AF_INET,SOCK_DGRAM,0);
if(sock_desc==-1)
{
printf("\nError in socket creation");
exit(1);
}
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
server.sin_port=3500;
k=bind(sock_desc,(struct sockaddr*)&server,sizeof(server));
if(k==-1)
{
printf("\nError in binding");
93 OS & Network Lab Record SCTCE
exit(1);
}
len=sizeof(server);
k=recvfrom(sock_desc,buf,sizeof(buf),0,(struct
sockaddr*)&server,&len);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
}
strcpy(snd,buf);
while(i<(strlen(buf)))
{
if(buf[i]=='@')
{
for(j=i+1;j<strlen(buf);j++)
domain[m++]=buf[j];
break;
}
i++;
}
printf("Receiving Mail...");
printf("\nDomain verified << %s >>",domain);
len=sizeof(server);
k=recvfrom(sock_desc,buf,sizeof(buf),0,(struct
sockaddr*)&server,&len);
if(k==-1)
{
printf("\nError in receiving");
exit(1);
}
printf("\nFROM: %s\n",buf);
Helo
QUIT
Server
Problem Description
sendfile (): This function is used to send a file between server and client.
system ()
Client
3. From the server the size of the file as well as the file is received in the variables
‘length’ and ‘fil’ respectively.
4. Write the received details into the filehandle which is the descriptor for the opened
file list2.txt
2. Create a socket and notify the server that LOAD is to be performed by using the send
command. Along with it send the name of the file to be downloaded.
3. From the server the size of the file as well as the file is received in the variables
‘length’ and ‘fil’ respectively
4. Write the received details into the filehandle which is the descriptor for the opened
file list3.txt.
1. Create a socket and bind to the port which is given as input from the user
3. For the LIST operation using the command system("ls -al>list.txt") get the details of
all the files along with its attributes into the file named list.txt.
stat ("list.txt",&obj);
sprintf (length,"%d",(int)obj.st_size);
6. Using the function sendfile () send the contents of list.txt to the client
1. For the LOAD operation the filename to be downloaded is specified by the client.
stat (filename,&obj);
sprintf (length,"%d",(int)obj.st_size);
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include<sys/stat.h>
#include<sys/sendfile.h>
#include <fcntl.h>
memset(&address1,0,sizeof(address1));
memset(&address2,0,sizeof(address2));
sock_descr=socket(AF_INET,SOCK_STREAM,0);
if(sock_descr==-1)
{
printf("socket creation failed");
exit(1);
}
address1.sin_family=AF_INET;
address1.sin_port=atoi(argv[1]);
address1.sin_addr.s_addr=INADDR_ANY;//inet_addr(argv[1]);
k=bind(sock_descr,(struct sockaddr*)&address1,sizeof(address1));
if(k==-1)
{
printf("binding error");
exit(1);
}
k=listen(sock_descr,5);
if(k==-1)
{
printf("listen failed");
exit(1);
}
len=sizeof(address2);
temp_descr=accept(sock_descr,(struct sockaddr*)&address2,&len);
while(1)
{
k=recv(temp_descr,buf,100,0);
if(k==-1)
{
printf("receive failed");
exit(1);
}
for(i=0;i<4;i++)
choice[i]=buf[i];
choice[4]='\0';
printf("\n%s",choice);
if(strcmp(choice,"LIST")==0)
{
system("ls -al>list.txt");
filehandle=open("list.txt",O_RDONLY);//
stat("list.txt",&obj);//
sprintf(length,"%d",(int)obj.st_size);
k=send(temp_descr,length,strlen(length),0);
if(k==-1)
{
printf("send failed");
exit(1);
}
k=sendfile(temp_descr,filehandle,NULL,obj.st_size);
if(k==-1)
{
printf("file sendingfailed");
exit(1);
}
}
if(strcmp(choice,"LOAD")==0)
{
strcpy(filename,buf+4);
stat(filename,&obj);
filehandle=open(filename,O_RDONLY);
if(filehandle==-1)
{
printf("NO SUCH FILE\n");
exit(1);
}
sprintf(length,"%d",(int)obj.st_size);
printf("\n%s\n",length);
k=send(temp_descr,length,strlen(length),0);
if(k==-1)
{
printf("send failed");
exit(1);
Client
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include<sys/stat.h>
#include<sys/sendfile.h>
#include <fcntl.h>
int main(int arc,char *argv[])
{
struct sockaddr_in address;
int sock_descr;
int k,choice,len,l,c=0,filehandle;
char buf[100],length[100],fil[100],filename[100];
memset(&address,0,sizeof(address));
sock_descr=socket(AF_INET,SOCK_STREAM,0);
if(sock_descr==-1)
{
printf("socket creation failed");
exit(1);
}
address.sin_family=AF_INET;
address.sin_port=atoi(argv[1]);
address.sin_addr.s_addr=INADDR_ANY;
k=connect(sock_descr,(struct sockaddr*)&address,sizeof(address));
if(k==-1)
{
printf("connecting failed");
exit(1);
}
while(1)
{
printf("\n1:LIST\n2:LOAD\n3:Exit : ");
scanf("%d",&choice);
switch(choice)
{
case 1:
filehandle=open("list2.txt",O_RDWR|O_CREAT,0700);
strcpy(buf,"LIST");
The main data item in any Unix-like system is the ``file'', and a unique pathname
identifies each file within a running system. Every file appears like any other file in the
way is accessed and modified: the same system calls and the same user commands
apply to every file. This applies independently of both the physical medium that holds
information and the way information is laid out on the medium. Abstraction from the
physical storage of information is accomplished by dispatching data transfer to
different device drivers; abstraction from the information layout is obtained in Linux
through the VFS implementation.
Linux looks at its file-system in the way UNIX does: it adopts the concepts of
super-block, inode, directory and file in the way Unix uses them. The tree of files that
can be accessed at any time is determined by how the different parts are assembled
together, each part being a partition of the hard drive or another physical storage device
that is ``mounted'' to the system.
The super-block owes its name to its historical heritage, from when the first
data block of a disk or partition was used to hold meta-information about the
partition itself. The super-block is now detached from the concept of data
block, but still is the data structure that holds information about each
mounted file-system. The actual data structure in Linux is called struct
super_block and hosts various housekeeping information, like mount flags,
mount time and device blocksize. The 2.0 kernel keeps a static array of such
structures to handle up to 64 mounted file-systems.
An inode is associated to each file. Such an ``index node'' encloses all the
information about a named file except its name and its actual data. The
The directory is a file that associates inodes to filenames. The kernel has no
special data structure to represent a directory, which is treated like a normal
file in most situations. Functions specific to each filesystem-type are used to
read and modify the contents of a directory independently of the actual
layout of its data.
The file itself is something that is associated to an inode. Usually files are data
areas, but they can also be directories, devices, FIFO's or sockets. An ``open
file'' is described in the Linux kernel by a struct file item; the structure
encloses a pointer to the inode representing the file. File structures are created
by system calls like open, pipe and socket, and are shared by father and child
across fork.
Problem Description
statvfs ()
This function obtains information about the file system containing the file
referred to by the specified path name.
2. The path of the filename whose status is to be found is stored in variable Path.
3. Using the function statvfs() status of the file system is obtained in the object data.
4. Now the required status info can be retrieved using Data.f_bsize, Data.f_blocks
etc.
5. Display the block size, free blocks size and used blocks in MB.
6. Stop
Disk /root:
What Is RPC
The easiest way to define and generate the protocol is to use a protocol complier
such as rpcgen. For the protocol you must identify the name of the service procedures,
and data types of parameters and return arguments.The protocol compiler reads a
definition and automatically generates client and server stubs. rpcgen uses its own
language (RPC language or RPCL) which looks very similar to preprocessor
directives. rpcgen exists as a standalone executable compiler that reads special files
denoted by
a .x prefix.
XDR is a standard for the description and encoding of data. It is useful for
transferring data between different computer architectures, and has been used to
communicate data between such diverse machines as the SUN WORKSTATION*,
VAX*, IBM-PC*, and Cray*.
XDR uses a language to describe data formats. The language can only be used
only to describe data; it is not a programming language. This language allows
one to describe intricate data formats in a concise manner. The alternative of using
graphical representations (itself an informal language) quickly becomes
incomprehensible when faced with complexity. The XDR language itself is similar to
the C language, just as Courier [4] is similar to Mesa. Protocols such as ONC RPC
(Remote Procedure Call) and the NFS* (Network File System) use XDR to describe the
format of their data.
The XDR standard makes the following assumption: that bytes (or octets)
are portable, where a byte is defined to be 8 bits of data. A given hardware device
should encode the bytes onto the various media in such a way that other hardware
devices may decode the bytes without loss of meaning. For example, the Ethernet*
standard suggests that bytes be encoded in "little-endian" style [2], or least significant
bit first.
What is rpcgen
The rpcgen tool generates remote program interface modules. It compiles source
code written in the RPC Language. RPC Language is similar in syntax and
structure to C. rpcgen produces one or more C language source modules, which are
then compiled by a C compiler. The default output of rpcgen is:
Various transports
struct finger_out{
char message[1024];
};
program FINGER
{
version FINGER_VERSION
{
finger_out MyFinger() = 1;
} = 1;
} = 0x21230000;
Problem Description
Develop a program to implement the finger utility using Remote Procedure Call
(RPC).
RPCGEN
Rpcgen is a tool that generates C code to implement an RPC protocol. The input
to rpcgen is a language similar to C known as, rpc language.
1. Start
2. Client makes a TCP connection to the server (default port 79) and transfers
parameters.
3. If input parameter is {c} only, print list of all users online and some additional
information like
terminal location
home location
idle time [no. of minutes since last typed input or since last job activity]
login information
5. If input is {u}{H}{c} where {h} is host H, then transfer the finger request to the
computer on behalf of this host.
6. Stop
Client
#include <rpc/rpc.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "finger.h"
void err_quit(char *msg)
{
printf("%s\n", msg);
exit(1);
}
int main(int argc, char* argv[])
{
CLIENT *c1;
finger_out *outp;
if(argc!=2)
err_quit("usage: client <hostname>");
c1 = clnt_create(argv[1], FINGER, FINGER_VERSION, "tcp");
if( (outp=myfinger_1(NULL, c1))==NULL )
err_quit(clnt_sperror(c1, argv[1]));
printf("result: %s\n", outp->message);
exit(0);
}
Server
#include <rpc/rpc.h>
SAMPLE INPUT/OUTPUT
Open the executable server file
Open the executable client file with arguments
./client 127.0.0.1 5000
root @example:~/Desktop/RPC$ ./client 127.0.0.1 5000
Login Name Tty Idle Login Time Office Office Phone
root root tty7 May 9 15:52 (:0)
root root pts/0 May 9 16:06 (:0.0)
root @example:~/Desktop/RPC$