cis620-3-11 - Cleveland State University

advertisement
CS 620 Advanced Operating
Systems
Lecture 3 – UNIX IPC Programming
Review
Professor Timothy Arndt
BU 331
UNIX Programming Review
• UNIX manages multiple concurrent
processes.
 Each process is represented by an entry in the
process table.
 A process goes through a number of states
before running to completion
•
•
•
•
Running
Asleep
Ready
Zombie
Process Creation
• The fork system call is used inside a C
program to create another process.
 After the fork call, both a parent and child
process are running.
 The child process has a unique PID, and PPID,
but otherwise is equivalent to the parent (i.e. it
is a copy of the same program).
 The PID is used to distinguish the child from
the parent process.
Process Creation
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
main()
{ int child_id;
child_id = fork();
/* process creation
*/
if ( child_id == 0 ) /* child code begin
*/
{
printf("Child says my pid = %d and my parent pid = %d\n",
getpid(), getppid());
_exit(0);
/* child terminates (i) */
}
/* child code end
*/
/* remaining parent code */
if ( child_id < 0 )
{
fprintf(stderr, "fork failed\n");
exit(1);
}
printf("Parent says child pid = %d\n", child_id);
}
Program Execution: exec
• The child process can also run a different
program than the parent by overlaying a
new executable file on itself.
 This is done using one of the exec routines:
execl, execv, execve, etc.
 The execed file can either be an executable
binary file or an executable text file (e.g. a shell
script).
 The various exec routines vary in the type and
number of arguments they take.
Exec Example
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define MAXLINE 80
int main()
{ char cmd[MAXLINE];
void background(char *cmd);
for (;;)
{
printf("mysh ready%%");
/* prompt
*/
fgets(cmd, MAXLINE, stdin); /* read command
*/
if ( strcmp(cmd,"exit") == 0 )
return(0);
background(cmd);
/* start background job */
}
}
Exec Example
#define WHITE "\t \n"
#define MAXARG 20
void background(char *cmd)
{ char *argv[MAXARG];
int id, i = 0;
/* to fill in argv */
argv[i++] = strtok(cmd, WHITE);
while ( i < MAXARG &&
(argv[i++] = strtok(NULL, WHITE)) != NULL );
if ( (id = fork()) == 0)
/* child executes background job */
{
execv(argv[0], argv);
_exit(1); /* execv failed */
}
else if ( id < 0 )
{
fprintf(stderr, "fork failed\n");
perror("background:");
}
}
Synchronization of Parent and
Child
 After creating a child process using fork, the
parent may run independently, or it may wait
for the child process to terminate before
proceeding further.
 The wait call searches for a terminated child (in
the zombie state) of the calling process.
 If there are no child processes, wait returns with a value of
-1
 If one or more child processes are in the zombie state, wait
selects an arbitrary child, frees its process table slot, stores
its exit status and returns it PID
 Otherwise, wait blocks until one of the child processes
terminates.
Synchronization of Parent and
Child
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{ int pid1, pid2, pid;
union wait status;
if ((pid1 = fork()) == 0)
/* child one */
{
printf("child pid=%d\n", getpid());
_exit(0);
}
printf("forking again\n");
if ((pid2 = fork()) == 0)
/* child two */
{
printf("child pid=%d\n", getpid());
_exit(1);
}
Synchronization of Parent and
Child
printf("first wait\n");
pid = wait(&status);
printf("pid=%d, status=%d\n", pid, status);
printf("2nd wait\n");
pid = wait(&status);
printf("pid=%d, status=%d\n", pid, status);
return(0);
}
More on Wait
• The waitpid system call can be used to
search for a particular child
 Another system call – waitid – provides even
more flexibility.
• The ‘status’ returned can be examined more
closely to get info about how the process
terminated by using one of several macros
 WEXITSTATUS(status), WIFSIGNALED(status),
WCOREDUMP(status), WSTOPSIG(status),
etc.
Interrupts and Signals
 Signals are used in UNIX to tell a running
process that some event has occurred.
 After receiving a signal, a process reacts to it in
a well-defined manner.
 There are a number of different signals that can
be sent: SIGHUP 1; SIGINT 2; SIGQUIT 3;
SIGILL 4; SIGTRAP 5; SIGFPE 8; SIGKILL
9; SIGBUS 10; SIGSEGV 11; SIGSYS 12;
SIGVTALRM 26; SIGPROF 27.
Interrupts and Signals
 From the shell, a signal can be sent using the
kill command with the signal to be sent along
with the PID.
 From a C program, the function raise sends a
signal to the same process, while the function
kill sends a signal to some other process.
 If a signal is not currently blocked by a process,
further occurrences of the signal are blocked
during signal handling.
Interrupts and Signals
 The function is suspended and the handler
function for the signal is called, and finally if
the handler function returns, the signal is
unblocked and normal execution of the process
resumes from the point of interrupt.
 After receiving a signal, a process normally
either exits or stops. This default behavior can
be changed using the signal function,
specifying a handler function for a specific
signal. When that signal is received, the handler
function will be invoked.
Signal Trapping
/* this program demonstrates the use of signal to trap
* interrupts from the terminal. To terminate the program
* type ^\
*/
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
main()
{ void cnt(int sig);
signal(SIGINT, cnt);
printf("Begin counting and INTERRUPTs\n");
for(;;); /* infinite loop */
}
void cnt(int sig)
{ static int count=0;
printf("Total of %d INTERRUPTS received\n", ++count);
IPC and Network
Communication
 Two processes residing either on the same
computer or on different computers may need
to exchange data. This is known as Inter
Process Communication (IPC).
 If the two processes are related by a fork, IPC
can be done through the pipe mechanism (the
processes are on the same machine).
 If the two processes are not related, IPC can be
performed using the socket mechanism.
Pipes
 A pipe is a direct (in memory) I/O channel
between processes.
 It is used with the calls fork, exec, wait, and
exit to make multiple processes cooperate.
 To establish a pipe use the system call int
pipe(int fildes[2])
• This establishes a buffer and two descriptors
fildes[0] for reading the pipe and fildes[1] for
writing the pipe.
• The pipe is created before the fork, so both parent
and child have copies of the pipe.
Pipes
 I/O is performed through a pipe using the read
and write calls.
 Read removes characters from the buffer and
write deposits them.
 The buffer size is usually 4096 characters.
 If we write a full pipe buffer, the process blocks
until more space is available in the pipe.
 If we read an empty buffer, the reading process
blocks unless the write end of the pipe has been
closed - in this case 0 (end of file) is returned.
Pipes
#include
#include
#include
#include
<stdio.h>
<unistd.h>
<string.h>
<sys/wait.h>
int main(int argc, char *argv[])
{ int p[2];
int i, pid, status;
char buffer[20];
pipe(p);
/* setting up the pipe
*/
if ((pid = fork()) == 0)
/* in child */
{ close(p[1]);
/* child closes p[1]
*/
while ((i = read(p[0], buffer, 6)) != 0)
{ buffer[i] = '\0';
/* string terminator
*/
printf("%d chars :%s: received by child\n", i, buffer);
}
_exit(0);
/* child terminates
*/
}
Pipes
/* in parent */
close(p[0]);
/* parent writes p[1]
*/
write(p[1], "Hello there,", sizeof("Hello there,"));
write(p[1], " from me.", sizeof(" from me."));
close(p[1]);
/* finished writing p[1] */
while (wait(&status)!=pid);
/* waiting for pid
*/
if (status == 0) printf("child finished\n");
else printf("child failed\n");
return(0);
}
The dup2 Command
• The following example shows the use of the
dup2 command which duplicates an existing
I/O descriptor.
Pipes
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{ int p[2];
int i,pid1,pid2, status;
argv++;
/* lose argv[0]
for (i = 1; i <= argc ; i++)
if (strcmp(argv[i],"%") == 0)
{
argv[i] = '\0';
/* break into two commands
break;
}
pipe(p);
/* setting up the pipe
if ((pid1 = fork ()) == 0)
/* child one
{
close(p[1]);
dup2(p[0],0);
/* 0 becomes a duplicate of p[0]
close(p[0]);
execv(argv[i+1], &argv[i+1]); /* this reads the pipe
*/
*/
*/
*/
*/
*/
Pipes
_exit(1);
/* bad error execl failed */
}
if ((pid2 = fork ()) == 0)
/* child two
{
close(p[0]);
dup2(p[1],1);
/* 1 becomes a duplicate of p[1]
close(p[1]);
execv(argv[0],argv);
/* this writes the pipe
_exit(1);
/* bad error execv failed
}
/* parent does not use pipe */
close(p[0]);
close(p[1]);
while (wait(&status)!=pid2);
/* waiting for pid2
if (status == 0) printf("child two terminated\n");
else printf("child two failed\n");
exit(0);
}
*/
*/
*/
*/
*/
Two-Way Pipe Connections
• In order to have two-way pipe connections
between two processes, two pipes must be
used. This is shown in the following
example.
Two-Way Pipe Connections
#include <stdio.h>
#include <string.h>
int readl(int fd, char s[], int size)
{ char *tmp = s;
while (0 < --size && read(fd, tmp, 1) != 0
&& *tmp++ != '\n');
*tmp = '\0'; /* string terminator */
return(tmp - s);
}
int pipe_2way(char *cmd[], int piped[])
{ int pid, wt[2], rd[2];
pipe(rd);
/* incoming pipe: read by parent */
pipe(wt);
/* outgoing pipe: write to child */
if ((pid=vfork()) == 0)
Two-Way Pipe Connections
{
close(wt[1]); /* in child */
dup2(wt[0],0);
/* 0 identified with wt[0]
close(wt[0]);
close(rd[0]);
dup2(rd[1], 1);
/* 1 identified with rd[1]
close(rd[1]);
execv(cmd[0],cmd);
/* execute given command
perror("execv failed"); /* normally not reached
_exit(1);
}
close(wt[0]); /* in parent */
piped[1] = wt[1];
close(rd[1]);
piped[0] = rd[0];
return(0);
}
*/
*/
*/
*/
Two-Way Pipe Connections
#define SIZE 256
int main()
{
int pd[2];
char *str[2];
char test_string[] = "IPC WITH TWO-WAY PIPE.\n";
char buf[SIZE];
char *tmp = buf;
str[0] = "./lowercase";
str[1] = NULL;
pipe_2way(str, pd);
/* write to lowercase process */
write(pd[1], test_string, strlen(test_string));
readl(pd[0], buf, SIZE); /* read from lowercase process */
printf("Received from lowercase process:\n%s", buf);
return(0);
}
Two-Way Pipe Connections
/***** The lowercase program *****/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFSIZE 1024
void lower(char *buf, int length)
{ while (length-- > 0)
{
*buf = tolower( *buf );
buf++;
}
}
Two-Way Pipe Connections
int main(int argc, char *argv[])
{ char buffer[BUFSIZE];
int nc;
while ((nc = read(0, buffer, BUFSIZE)) > 0)
{
lower(buffer,nc);
nc = write(1, buffer, nc);
if (nc == -1) break;
}
if (nc == -1)
{
perror(argv[0]);
exit(1);
}
return(0);
}
Named Pipes
• Linux provides a similar IPC mechanism
called named pipes (or FIFOs).
 Can be used to communicate between 2
unrelated processes
•
•
•
•
•
Have an entry in the (file) directory
Create using mknod (from shell or program)
Have permissions (like files)
Survive the end of a program (like files)
Must be explicitly removed (like files)
Sockets
 Sockets are abstractions that serve as endpoints
of communication within a networking domain.
 The socket is the ipc mechanism’s interface to
application programs. Each socket can
exchange data with any other socket within the
same domain (e.g. the Internet domain).
 Each socket is assigned a type property.
Different type sockets use different protocols.
• Stream sockets support bidirectional, reliable,
sequenced flow of data
 Stream sockets in the Internet domain use TCP/IP.
Sockets
 Datagram sockets provide bidirectional flow of data
packets called messages
• The communication channel is not sequenced, reliable, or
unduplicated
• A datagram socket does not have to be connected to a peer
• A message is sent to a datagram socket by specifying its
address
• Datagram sockets in the Internet domain use UDP/IP.
 Raw sockets give access to the underlying
communications protocol
• They are not intended for the general user
• In the Internet domain, they give direct access to the Internet
Protocol (IP).
Sockets
 The socket system call creates a socket of a
particular type in a particular domain
• The type and domain are given by constants defined
in sys/socket.h
 Sockets must then be given an address so that
other processes can refer to them
• In Internet domain, socket address consists of
combination of host IP address and port number
• Standard network services are assigned the same
port number on each host
• A database file contains a list of services and port
number.
Sockets
grail:/users/faculty/arndt> cd /etc
grail:/etc> more services
…
daytime
13/tcp
daytime
13/udp
qotd
17/tcp
quote
qotd
17/udp
quote
msp
18/tcp
msp
18/udp
chargen
19/tcp
ttytst source
chargen
19/udp
ttytst source
ftp-data
20/tcp
ftp-data
20/udp
# 21 is registered to ftp, but also used by fsp
ftp
21/tcp
ftp
21/udp
fsp fspd
ssh
22/tcp
ssh
22/udp
telnet
23/tcp
telnet
23/udp
# 24 - private mail system
lmtp
24/tcp
lmtp
24/udp
smtp
25/tcp
mail
…
# message send protocol
# message send protocol
# SSH Remote Login Protocol
# SSH Remote Login Protocol
# LMTP Mail Delivery
# LMTP Mail Delivery
Sockets
• To bind a name to socket, use the system
call bind(int soc, struct sockaddr *addr, int
addrlen)
• The following example illustrates the use of
datagram sockets with a sender process and
a receiver process.
Datagram Sockets
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h>
/* UNIX domain header */
int main()
{ int soc;
char buf[] = "Hello there";
const char *NAME = "./receiver_soc";
struct sockaddr_un peer;
/* (1) */
int n;
peer.sun_family = AF_UNIX;
strcpy(peer.sun_path, NAME);
soc = socket(AF_UNIX, SOCK_DGRAM, 0);
/* (2) */
Datagram Sockets
if ( access(peer.sun_path, F_OK) > -1 )
/* (3) */
{
n = sendto(soc, buf, strlen(buf),
/* (4) */
0, (struct sockaddr *)&peer, sizeof(peer));
if ( n < 0 )
{ fprintf(stderr, "sendto failed\n");
exit(1);
}
printf("Sender: %d characters sent!\n", n); /* (5) */
close(soc);
/* (6) */
}
return(0);
}
Datagram Sockets
/***** File : receiver.c
*****/
/***** datagram socket example: receiver process *****/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
/* UNIX domain header */
void cleanup(int soc, char *file)
{
close(soc);
unlink(file);
}
Datagram Sockets
int main()
{ int soc;
char buf[64];
const char *NAME = "./receiver_soc2";
struct sockaddr_un self; /* (A) */
struct sockaddr_un peer;
int n, len;
self.sun_family = AF_UNIX;
strcpy(self.sun_path, NAME);
soc = socket(AF_UNIX, SOCK_DGRAM, 0);
/* (B) */
n = bind(soc, (const struct sockaddr *)&self, sizeof(self));
if ( n < 0 )
{ fprintf(stderr, "bind failed\n");
exit(1);
}
n = recvfrom(soc, buf, sizeof(buf),
/* (D) */
0, (struct sockaddr *)&peer, &len);
Datagram Sockets
if ( n < 0 )
{ fprintf(stderr, "recvfrom failed\n");
cleanup(soc, self.sun_path);
exit(1);
}
buf[n] = '\0';
printf("Datagram received = %s\n", buf);
cleanup(soc, self.sun_path);
return(0);
}
/* (E) */
/* (F) */
Datagram Sockets
• Note that we have two separate processes
(we have two main functions). Both must be
compiled.
• In order to run the example, both processes
must be launched:
receiver &
sender
• The sendto and recvfrom system calls are
normally used with datagram sockets.
Stream Sockets
 A stream socket is connected with its peer to
form a two-way pipe between a client and a
server.
• The server process listens for connection requests
and accepts connections.
 The server process binds a known address to a socket.
• The client process uses its socket to initiate a
connection to a socket of a server process.
 The client process finds the correct address of the server.
 Then initiates a connection to the server process.
• After connection, data communication takes place
using the read and write I/O system calls.
Stream Sockets
 The connect system call - connect(int soc,
struct sockaddr *name, int namelen) associates the client socket given by the
descriptor soc to a peer socket in a server
specified by *name.
 The connect call is often used by client
programs to connect to stream sockets of
known services on the Internet.
 A pair of sockets forms a virtual circuit
between the client and server process.
Stream Sockets
 A server process with a stream socket needs to
take the following steps to get ready to accept a
connection:
• Create a socket in the appropriate domains of type
SOCK_STREAM
• Construct the correct address and bind it to the
socket
• Indicate a willingness to accept connection requests
by executing the listen system call.
• Use the accept call to wait for a connection request
and establish a connection.
Stream Sockets
 int listen(int soc, int n) initializes the
socket for incoming requests and sets the
maximum number of pending connections.
 int accept(int soc, struct sockaddr
*addr, int *addrlen) accepts connections
on the socket on which a listen has been
executed
• If there are pending connections, the first is chosen
and a new socket is created with the same properties
as soc
 This socket is connected and a descriptor of the socket is
returned.
Stream Sockets
 The listening socket remains ready to receive
connection requests.
 If no connections are pending and the socket is
not marked as nonblocking (using system call
fcntl), accept blocks until a connection
request arrives.
 If the connection is marked as nonblocking and
no requests are pending, accept returns an
error.
• The accepted socket communicates with its peer and
may not accept additional connections.
Stream Sockets
 For connected sockets, the basic read and
write system calls send and receive data:
• write(soc, buffer, sizeof(buffer));
• read(soc, buffer, sizeof(buffer));
 Each process reads and writes its own socket,
resulting in a bidirectional data flow between
the connected peers. The socket I/O calls
• send(soc, buffer, sizeof(buffer), opt);
• recv(soc, buffer, sizeof(buffer), opt);
 Can be used by stream sockets to send out-ofband data by setting opt to MSG_OOB.
Stream Socket Example
/***** stream socket example: server.c *****/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
/* UNIX domain header */
#include <stdlib.h>
#include <stdio.h>
int main()
{ int soc, ns, k;
char buf[256];
struct sockaddr_un self = {AF_UNIX, "serversoc"};
struct sockaddr_un peer = {AF_UNIX};
int peer_len = sizeof(peer);
/* set up listening socket soc */
soc = socket(AF_UNIX, SOCK_STREAM, 0);
/* (1) */
if (soc < 0)
{ perror("server:socket"); exit(1);
}
Stream Socket Example
if (bind(soc, (struct sockaddr *)&self, sizeof(self)) == -1)
{ perror("server:bind"); close(soc);
exit(1);
}
listen(soc, 1);
/* accept connection request */
ns = accept(soc, (struct sockaddr *)&peer,
&peer_len);
if (ns < 0)
{ perror("server:accept"); close(soc);
unlink(self.sun_path);
exit(1);
}
/* data transfer on connected socket ns */
k = read(ns, buf, sizeof(buf));
printf("SERVER RECEIVED: %s\n", buf);
write(ns, buf, k);
close(ns);
close(soc); unlink(self.sun_path);
return(0); }
Stream Socket Example
/***** File : client.c
*****/
/***** socket example: receiver process *****/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
/* UNIX domain header */
int main()
{ int soc; char buf[256];
struct sockaddr_un self={AF_UNIX, "clientsoc"};
struct sockaddr_un peer={AF_UNIX, "serversoc"};
soc = socket(AF_UNIX, SOCK_STREAM, 0);
bind(soc, (struct sockaddr *)&self, sizeof(self));
/* request connection to serversoc */
if (connect(soc, (struct sockaddr *)&peer,
sizeof(peer)) == -1)
{ perror("client:connect"); close(soc);
Stream Socket Example
unlink(self.sun_path); exit(1);
}
write(soc, "hello from client", 18);
read(soc, buf, sizeof(buf));
printf("SERVER ECHOED: %s\n", buf);
close(soc);
unlink(self.sun_path);
return(0);
}
/*** end of client.c ***/
Stream Socket Example
• Note that it is not strictly necessary to bind
an explicit address for a client process
• The close system call closes both halves of
a socket
• To close the read and write halves
independently, the shutdown system call can
be used
Network Databases and
Address Mapping
 The previous example programs involved
sockets with UNIX domain addresses - a simple
name
 For Internet domain sockets, the socket address
involves both the numeric IP address of a host
as well as a port number for a particular server
 The DNS, a set of database files, and a
collection of library functions combine to help
construct required Internet socket addresses in
application programs
Network Databases and
Address Mapping
 Some of the important files for name resolution
are:
• /etc/resolv.conf - the configuration file for the DNS
resolver. Lists name servers for the local domain.
• /etc/named.boot - the DNS name server boot file.
Needed only on a host that runs a name server.
Gives the locations of root name servers, e-mail
exchange information, etc.
• /etc/services - contains information regarding well
known Internet services.
• /etc/protocols - contains information regarding
known Internet protocols.
Network Databases and
Address Mapping
grail:/etc> more /etc/resolv.conf
search cba.csuohio.edu csuohio.edu
nameserver 137.148.49.12
nameserver 137.148.49.11
grail:/etc> more named.boot
;
; type
domain
source file
;
directory
/etc/named.data ; running directory for named
primary
0.0.127.IN-ADDR.ARPA
db.127.0.0
primary
cba.csuohio.edu
db.cba
primary
20.148.137.IN-ADDR.ARPA db.137.148.20
secondary
csuohio.edu
137.148.5.2 db.137.148
cache
.
db.cache
primary
21.148.137.IN-ADDR.ARPA db.137.148.21
Network Databases and
Address Mapping
grail:/etc> more /etc/protocols
# /etc/protocols:
# $Id: protocols,v 1.6 2007/05/23 15:55:03 pknirsch Exp $
#
# Internet (IP) protocols
#
#
from: @(#)protocols
5.1 (Berkeley) 4/17/89
#
# Updated for NetBSD based on RFC 1340, Assigned Numbers (July 1992).
#
# See also http://www.iana.org/assignments/protocol-numbers
ip
0
number
hopopt 0
icmp
1
igmp
2
ggp
3
ipencap 4
``IP'’)
IP
# internet protocol, pseudo protocol
HOPOPT
ICMP
IGMP
GGP
IP-ENCAP
#
#
#
#
#
hop-by-hop options for ipv6
internet control message protocol
internet group management protocol
gateway-gateway protocol
IP encapsulated in IP (officially
Network Databases and
Address Mapping
st
tcp
cbt
5
ST
6
TCP
7
CBT
<A.Ballardie@cs.ucl.ac.uk>
egp
8
EGP
igp
9
IGP
IGRP)
bbn-rcc 10
BBN-RCC-MON
# Network Voice Protocol
pup
12
PUP
argus
13
ARGUS
emcon
14
EMCON
xnet
15
XNET
chaos
16
CHAOS
udp
17
UDP
mux
18
MUX
dcn
19
DCN-MEAS
hmp
20
HMP
prm
21
PRM
…
# ST datagram mode
# transmission control protocol
# CBT, Tony Ballardie
# exterior gateway protocol
# any private interior gateway (Cisco: for
# BBN RCC Monitoringnvp
#
#
#
#
#
#
#
#
#
#
11
PARC universal packet protocol
ARGUS
EMCON
Cross Net Debugger
Chaos
user datagram protocol
Multiplexing protocol
DCN Measurement Subsystems
host monitoring protocol
packet radio measurement protocol
NVP-II
Network Databases and
Address Mapping
 The name resolver can be used in an application
program by a set of standard routines.
• The library function gethostbyname:
#include <netdb.h>
hostent *gethostbyname(char *host)
• given a host name (a string) returns a pointer to a
hostent structure
struct hostent
{ char *h_name; /* official name of the host */
char **h_aliases; /* aliases */
int h_addrtype; /* address type: AF_INET */
int h_length; /* length of address */
char **h_addr_list; /* IP addresses */
};
Network Databases and
Address Mapping
 The IP address can then be copied into the
sin_addr field of a sockaddr_in structure for a
target socket.
 To determine the port number for standard
network services use:
struct servent *getservbyname(char *service, char
*proto)
struct servent
{ char *s_name; /* official name of service */
char **s_aliases; /* alias list */
int s_port; /* port number: network byte order */
char *s_proto; /* protocol used */ };
Internet Stream Socket
Example
/***** inetserver.c *****/
#include <stdlib.h>
/* for getenv */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Internet domain header */
#include <strings.h>
#define SERVER_PORT 59154
struct sockaddr_in self = {AF_INET};
int main()
{ int soc, ns, k;
char buf[256];
struct sockaddr_in peer = {AF_INET};
int peer_len = sizeof(peer);
char *host;
/* set up listening socket soc */
Internet Stream Socket
Example
soc = socket(AF_INET, SOCK_STREAM, 0);
if (soc < 0)
{ perror("server:socket"); exit(1);
}
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_addr.s_addr = htonl(INADDR_ANY);
self.sin_port = htons(SERVER_PORT);
if (bind(soc, (struct sockaddr *)&self,
sizeof(self)) == -1)
{ perror("server:bind"); close(soc); exit(1); }
listen(soc, 1);
/* accept connection request */
ns = accept(soc, (struct sockaddr *)&peer, &peer_len);
if (ns < 0)
{ perror("server:accept"); close(soc); exit(1); }
/* data transfer on connected socket ns */
Internet Stream Socket
Example
k = read(ns, buf, sizeof(buf));
host = getenv("HOST");
printf("SERVER ON %s RECEIVED: %s\n”,
host, buf);
write(ns, buf, k);
close(ns);
close(soc);
return(0);
}
/***** inetclient.c *****/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Internet domain header */
#include <netdb.h>
Internet Stream Socket
Example
#include <strings.h>
#define SERVER_PORT 59154
struct sockaddr_in peer = {AF_INET};
int main(int argc, char* argv[])
{ int soc;
char buf[256];
struct hostent *hp;
if ( argc != 2 )
{ fprintf(stderr, "Usage: %s hostname\n", argv[0]);
exit(1);
}
/* fill in peer address */
hp = gethostbyname(argv[1]);
if ( hp == NULL )
{ fprintf(stderr, "%s: %s unknow host\n",
argv[0], argv[1]);
Internet Stream Socket
Example
exit(1);
}
bzero(&peer, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_addr.s_addr = htonl(INADDR_ANY);
peer.sin_port = htons(SERVER_PORT);
bcopy(hp->h_addr_list[0],
(char*)&peer.sin_addr, hp->h_length);
/* create socket */
soc = socket(AF_INET, SOCK_STREAM, 0);
/* request connection to server */
if (connect(soc, (struct sockaddr *)&peer,
sizeof(peer)) == -1)
{ perror("client:connect"); close(soc); exit(1); }
write(soc, "Hello Internet", 15);
read(soc, buf, sizeof(buf));
printf("SERVER ECHOED: %s\n", buf);
close(soc); return(0);
Download