cs 620 advanced operating systems lecture 3 – unix ipc programming review professor timothy arndt...

Post on 22-Dec-2015

226 Views

Category:

Documents

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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);

signal(SIGINT, cnt); }

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 <stdio.h>#include <unistd.h>#include <string.h>#include <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 256int 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 /etcgrail:/etc> more services…daytime 13/tcpdaytime 13/udpqotd 17/tcp quoteqotd 17/udp quotemsp 18/tcp # message send protocolmsp 18/udp # message send protocolchargen 19/tcp ttytst sourcechargen 19/udp ttytst sourceftp-data 20/tcpftp-data 20/udp# 21 is registered to ftp, but also used by fspftp 21/tcpftp 21/udp fsp fspdssh 22/tcp # SSH Remote Login Protocolssh 22/udp # SSH Remote Login Protocoltelnet 23/tcptelnet 23/udp# 24 - private mail systemlmtp 24/tcp # LMTP Mail Deliverylmtp 24/udp # LMTP Mail Deliverysmtp 25/tcp mail…

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'; /* (E) */ printf("Datagram received = %s\n", buf); /* (F) */ cleanup(soc, self.sun_path); return(0);}

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-of-band 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.confsearch cba.csuohio.edu csuohio.edunameserver 137.148.49.12nameserver 137.148.49.11grail:/etc> more named.boot;; type domain source file;directory /etc/named.data ; running directory for namedprimary 0.0.127.IN-ADDR.ARPA db.127.0.0primary cba.csuohio.edu db.cbaprimary 20.148.137.IN-ADDR.ARPA db.137.148.20secondary csuohio.edu 137.148.5.2 db.137.148cache . db.cacheprimary 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 IP # internet protocol, pseudo protocol number

hopopt 0 HOPOPT # hop-by-hop options for ipv6icmp 1 ICMP # internet control message protocoligmp 2 IGMP # internet group management protocolggp 3 GGP # gateway-gateway protocolipencap 4 IP-ENCAP # IP encapsulated in IP (officially

``IP'’)

Network Databases and Address Mapping

st 5 ST # ST datagram modetcp 6 TCP # transmission control protocolcbt 7 CBT # CBT, Tony Ballardie

<A.Ballardie@cs.ucl.ac.uk>egp 8 EGP # exterior gateway protocoligp 9 IGP # any private interior gateway (Cisco: for

IGRP)bbn-rcc 10 BBN-RCC-MON # BBN RCC Monitoringnvp 11 NVP-II

# Network Voice Protocolpup 12 PUP # PARC universal packet protocolargus 13 ARGUS # ARGUSemcon 14 EMCON # EMCONxnet 15 XNET # Cross Net Debuggerchaos 16 CHAOS # Chaosudp 17 UDP # user datagram protocolmux 18 MUX # Multiplexing protocoldcn 19 DCN-MEAS # DCN Measurement Subsystemshmp 20 HMP # host monitoring protocolprm 21 PRM # packet radio measurement protocol…

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 59154struct 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 59154struct 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);}

top related