Systems Programming III (Pipes and Socket Programming

Iqbal Mohomed CSC 209 – Summer 2004 Week 8

Inter-Process Communication (IPC)
• Data exchange techniques between processes:
– Message passing: files, pipes, sockets – Shared-memory model

Some Limitations • Limitations of files for inter-process data exchange: – Slow! • Limitations of pipes: – two processes must be running on the same machine – two processes communicating must be “related” • Sockets overcome these limitations and are widely used in Internet software .

Pipes and File • A fork’d child inherits file descriptors from its parent • Its possible to alter these using fclose() and fopen(): fclose(stdin). using dup() or dup2() . “r”). • One could exchange two entries in the fd table by closing and reopening both streams. FILE* fp = fopen(“/tmp/junk”. but there’s a more efficient way.

} • • • • In both cases. if (newFD < 0) {perror(“dup”). newFD). .dup() and dup2() newFD = dup( oldFD).exit(1). if (returnCode < 0) {perror(“dup”). it is first automatically closed Note that dup() and dup2() refer to FDs and not streams A useful system call to convert a stream to a FD is: int fileno( FILE*fp). oldFD and newFD now refer to the same file For dup2. if newFD is open.} • Or.exit(1). to force the newFD to have a specific number: returnCode = dup2(oldFD.

pipe() • The pipe() system call creates an internal system buffer and two file descriptors: one for reading and one for writing • With a pipe. typically want the stdout of one process to be connected to stdin of another process … this is where dup2() becomes useful! • Usage: int fd[2]. fd[1] for writing */ • Getting a stream from an FD: FILE* fdopen(int filedes.const char* mode). . pipe(fd). /* fd[0] for reading.

close(fd[1]).fileno(stdin)).(char*) 0). fileno(stdin)).fileno(stdout))."r"). dup2(fileno(fp). close(fd[0]).(char*)0). close(fd[0]). } return 0.exit(2).h> int main() { int fd[2].close(fd[1]). FILE *fp = fopen("file1"."uniq". fclose(fp)."sort". }else{ dup2(fd[0]. pipe(fd). execl("/bin/sort". } . if (fork() == 0) { dup2(fd[1].exit(3). execl("/usr/bin/uniq".pipe()/dup2() example /* Equivalent to "sort < file1 | uniq*/ #include<stdio.

my name is Iqbal. Iqbal. werewolf:~/iqtesty% sort<file1 Hello. is my name Output . my name is Marc. is is my my name name werewolf:~/iqtesty% sort < file1|uniq OR werewolf:~/iqtesty% . Marc. Hello.werewolf:~/iqtesty% cat file1 Hello./a. Hello. Marc.out Hello. Iqbal.

• Warning: popen() can return NULL too! . const char* type).c”.”r”).popen() and pclose() • popen() simplifies the sequence of: – – – – Generating a pipe Forking a child process Duplicating file descriptors Passing command execution via an exec() • Usage: FILE* popen(const char* command. • Example: FILE* pipeFP. pipeFP = popen(“/usr/bin/ls *.

with the advantages that processes don’t need to be related.What are sockets? • Sockets are an extension of pipes. the UNIX kernel implements pipes as a pair of sockets • Two (or more) sockets must be connected before they can be used to transfer data . or even on the same machine • A socket is like the end point of a pipe – in fact.

and SOCK_RAW … we’ll focus on SOCK_STREAM . SOCK_DGRAM.More on Sockets • Two main categories of socket types: – The UNIX domain: both processes on same machine – The INET domain: processes on different machines • Three main types of sockets: SOCK_STREAM.

Assign a name to the socket bind() 3. Extract connection from queue Established! accept() 5.Connection-Oriented Paradigm SERVER 1. Communicate! read() write() CLIENT 1. Establish a queue for connections listen() 4. Communicate! read() write() . Initiate a connection connect() 3. Create a socket socket() 2. Create a socket socket() 2.

SOCK_RAW • Protocol: – Set to 0 except for RAW sockets • Returns a socket descriptor .Creating the Socket int socket(int family. int protocol). SOCK_DGRAM. int type. • Family specifies the protocol family: – PF_INET – IPv4 – PF_LOCAL – UNIX Domain • Type: – SOCK_STREAM.

char sin_zero[8]. socklen_t addrlen). } • sin_addr can be set to INADDR_ANY to communicate with any host . • sockfd – returned by socket • INET Address struct sockaddr_in{ short sin_family. /*PF_INET*/ u_short sin_port.Bind to a name (Server Side) int bind(int sockfd. struct in_addr sin_addr. const struct sockaddr *servaddr.

int backlog) • After calling listen.Set up queue (Server Side) int listen (int sockfd. a socket is ready to accept connections • Prepares a queue in the kernel where partially completed connections wait to be accepted • backlog is the maximum number of partially completed connections that the kernel should queue .

Establish the connection (Server Side) int accept(int sockfd. socklen_t * addrlen). struct sockaddr* cliaddr. • Blocks waiting for a connection (from the queue) • Returns a new descriptor which refers to the TCP connection with the client • sockfd is the listening socket • cliaddr is the address of the client • Reads and writes on the connection will use the socket returned by accept .

socklen_t addrlen). • The kernel will choose a dynamic port and source IP address • Returns 0 on success and –1 on failure. setting errno . const struct sockaddr *servaddr.Establish the connection (Client Side) int connect(int sockfd.

but in the INET domain. strcpy(serv_adr.sin_addr. serv_adr. serv_adr. serv_adr.s_addr = htonl(INADDR_ANY).sin_port = htons(6789).cdf”).NAME).INET vs UNIX Domain • The main difference is the bind()/connect command … in the UNIX domain. serv_adr. host = gethostbyname(“werewolf.sun_family = AF_UNIX. the socket name is a machine name and port number: static struct sockaddr_in serv_adr.sin_family = AF_INET. memset(&serv_adr. • • AF_INET/PF_INET versus AF_UNIX/PF_UNIX Client needs to know the machine name and port of the server: struct hostent *host.sun_path. . VERSUS #define NAME “my_sock” static struct sockaddr_un serv_adr. sizeof (serv_adr)). 0. the socket name is a filename.

Network byte order • Intel CPUs are usually little-endian. • There are functions provided to do this: – – – – unsigned long htonl(unsigned long) unsigned short htons(unsigned short) unsigned long ntohl(unsigned long) unsigned short ntohs(unsigned short) . and Sun Sparc CPUs are big-endian • To communicate between machines with unknown or different “endian-ness” we convert numbers to network byte order (big-endian) before we send them.

Port Numbers • Well-known ports: 0 – 1023 – – – – 80: web 22: ssh 23: telnet 21: ftp • Registered ports: 1024 – 49151 • Private ports: 49152 .65535 .

Sign up to vote on this title
UsefulNot useful