TDC 561 Network Programming Week 3 Unix Asynchronous

  • Slides: 33
Download presentation
TDC 561 Network Programming Week 3: Unix Asynchronous Events; Signals and Alarms API Server

TDC 561 Network Programming Week 3: Unix Asynchronous Events; Signals and Alarms API Server Concurrency: Select () ; I/O Multiplexing; Camelia Zlatea, Ph. D Email: czlatea@cs. depaul. edu Distributed Systems Frameworks (DS 520 -95 -103) DISC’ 99

References § W. Richard Stevens, Network Programming : Networking API: Sockets and XTI, Volume

References § W. Richard Stevens, Network Programming : Networking API: Sockets and XTI, Volume 1, 2 nd edition, 1998 (ISBN 013 -490012 -X) – Chap. 6 ( I/O Multiplexing) § John Shapley Gray, Interprocess Communications in UNIX - The Nooks and Crannies Prentice Hall PTR, NJ, 1998 – Chap. 2, 4 (signals); Chap 10. 6 ( I/O Multiplexing ) § Douglas Comer, David Stevens, Internetworking with TCP/IP : Client-Server Programming, Volume III (BSD Unix and ANSI C), 2 nd edition, 1996 (ISBN 0 -13 -260969 -X) – Chap. 3, 4, 5 Network Programming (TDC 561) Winter 2003 Page 2

Unix System Programming - Topics Asynchronous Events Signals; Alarms; Distributed Systems Frameworks (DS 520

Unix System Programming - Topics Asynchronous Events Signals; Alarms; Distributed Systems Frameworks (DS 520 -95 -103) DISC’ 99

Asynchronous Events § Examples of process events: – a signal from another process –

Asynchronous Events § Examples of process events: – a signal from another process – an interrupt from a device – completion of a I/O request § Signals are events delivered to a process via UNIX. The process has no control over when they arrive. Signals are understood as software version of hardware interrupts. § Signals can be generated by: – hardware: ex: division by zero, illegal address access – kernel: ex: completion of a I/O request issued by the waiting process – user processes: ex: communication among processes related to relevant events, child termination notified to parent – user actions: ex: pressing the keyboard sequence for: quit, interrupt § To find the current mapping of the key sequences for various signals, call shell command: stty -a – Example: SIGINT is mapped to "ctrl + c" (or DEL) Network Programming (TDC 561) Winter 2003 Page 4

Unix System Calls to handle signals § Signal system call is used to install

Unix System Calls to handle signals § Signal system call is used to install signal handlers. /* legacy UNIX API */ #include <signal. h> void (*signal(int signo, void (*handler)(int)))(int); #include <signal. h> void (*sigset (int sig_no, void (*handler)(int)))(int); – The second parameter of the signal system call is a pointer to a function that returns void and takes a single integer as its argument, and the return value of signal itself is a pointer to a function that returns void and takes a single integer argument. – The second parameter to signal is a pointer to the function to call whenever the signal is delivered. – The return value is the previous signal handler that was installed before the new one was added. Network Programming (TDC 561) Winter 2003 Page 5

Signal Acceptance § § Signals can be generated by outside events. When a process

Signal Acceptance § § Signals can be generated by outside events. When a process receives a signal then the following actions can be taken: 1. ignore the signal 2. terminate the process (the default action SIG_DFL) 3. process the signal - take a particular action Network Programming (TDC 561) Winter 2003 Page 6

Signal Acceptance 1. Ignore the signal Program that ignores control-C. When an INT signal

Signal Acceptance 1. Ignore the signal Program that ignores control-C. When an INT signal (control-C) is Received, the process ignores it (SIG_IGN is the handler) #include <stdio. h> #include <sys/types. h> #include <signal. h> int main (void) { signal (SIGINT, SIG_IGN); while(1) { printf("Hellon"); } } Network Programming (TDC 561) Winter 2003 Page 7

Signal Acceptance 2. Terminate the process (the default action SIG_DFL) Default action (see manual

Signal Acceptance 2. Terminate the process (the default action SIG_DFL) Default action (see manual pages man signal) is the action executed if nothing else #include <iostream. h> #include <signal. h> int main() { signal(SIGINT, SIG_DFL); /* catch signal SIGINT=2 */ pause(); /* wait for a signal interruption */ } Network Programming (TDC 561) Winter 2003 Page 8

Signal Acceptance 3. Handle the signal - Take a particular action » » »

Signal Acceptance 3. Handle the signal - Take a particular action » » » The target process executes the action associated with the signal. Processing the signal depends also on the state of the process and level of priority. Signals can be caught by specifying a signal catching routine. The signals SIGKILL and SIGSTOP are never caught and they always terminate a process. #include <stdio. h> #include <sys/types. h> #include <signal. h> void action (int sig){ signal (SIGINT, action); int main (void){ signal (SIGINT, action); while(1) { printf("Hellon"); printf ("control-C won't stop this process!n"); } } } Network Programming (TDC 561) Winter 2003 Page 9

Signal Handling Example #include <stdio. h> #include <signal. h> /* signal handler function */

Signal Handling Example #include <stdio. h> #include <signal. h> /* signal handler function */ void action(int sig_no) { signal(sig_no, action); fprintf(stderr, "Catch signal: %dn", sig_no); } int main() { signal(SIGINT, action); signal(SIGALRM, SIG_DFL); signal(SIGTERM, SIG_IGN); pause(); /* wait for a signal interruption */ } Network Programming (TDC 561) Winter 2003 Page 10

Alarm Handling § Alarm system function § Sets a timer for the caller process

Alarm Handling § Alarm system function § Sets a timer for the caller process and generates SIGALRM (signal number 14) after the specified number of seconds have passed. #include <unistd. h> unsigned alarm(unsigned nosec); Network Programming (TDC 561) Winter 2003 Page 11

Alarm Handling § Example, alarm system calls cannot be stacked: alarm(10); alarm(20); // when

Alarm Handling § Example, alarm system calls cannot be stacked: alarm(10); alarm(20); // when this system call is invoked // the previous pending // alarm signal is canceled; // the timer is set to 20 sec alarm(0); int main(void) { // this system call reset the timer, // any pending alarm system call is canceled alarm(20); while (1) fprintf(stderr, "Hellon"); } Network Programming (TDC 561) Winter 2003 Page 12

Example of Handling Time-out Situations #include <stdio. h> #include <unistd. h> #include <signal. h>

Example of Handling Time-out Situations #include <stdio. h> #include <unistd. h> #include <signal. h> void timeout() { fprintf(stderr, "Timeout errorn"); int main(void) { char buf[256]; exit(0); } int n; signal(SIGALRM, timeout); alarm(30); // set timer while ((n=read(0, buf, sizeof(buf))<0) ; alarm(0); // reset timer exit(0); } Network Programming (TDC 561) Winter 2003 Page 13

Server Concurrency § For Servicing Multiple Clients there are two main approaches: – forking

Server Concurrency § For Servicing Multiple Clients there are two main approaches: – forking with fork() – selecting with select() § fork() approach forks a new process to handle each incoming client connection – Issues with zombies created when parent loops back to accept() a new client (ignore SIGCHILD signal) – Inefficient ( high overhead due to context switching) § A better approach would be to have a single process handle all incoming clients, without having to spawn separate child “server handlers”. select(). Network Programming (TDC 561) Winter 2003 Page 14

I/O Multiplexing § Monitoring multiple descriptors: – a server that handles both TCP and

I/O Multiplexing § Monitoring multiple descriptors: – a server that handles both TCP and UDP – a generic TCP client (like telnet) need to be able to handle unexpected situations, such as a server that shuts down without warning. » Input from standard input should be sent to a TCP socket. » Input from a TCP socket should be sent to standard output. – Non-determinism and Concurrency Problem: » How do we know when to check for input from each source? Network Programming (TDC 561) Winter 2003 Page 15

Solutions for Concurrency and I/O Non-determinism § Use nonblocking I/O – use fcntl() to

Solutions for Concurrency and I/O Non-determinism § Use nonblocking I/O – use fcntl() to set O_NONBLOCK § Use alarm and signal handler to interrupt slow system calls. § Use multiple processes/threads. § Use functions that support checking of multiple input sources at the same time. Network Programming (TDC 561) Winter 2003 Page 16

Non blocking I/O § use fcntl() to set O_NONBLOCK: #include <sys/types. h> #include <fcntl.

Non blocking I/O § use fcntl() to set O_NONBLOCK: #include <sys/types. h> #include <fcntl. h> int flags; flags = fcntl(sock, F_GETFL, 0); fcntl(sock, F_SETFL, flags | O_NONBLOCK); § Now calls to read() (and other system calls) will return an error and set errno to EWOULDBLOCK. Network Programming (TDC 561) Winter 2003 Page 17

while (! done) { if ( (n=read(STDIN_FILENO, …)<0)) if (errno != EWOULDBLOCK) /* ERROR

while (! done) { if ( (n=read(STDIN_FILENO, …)<0)) if (errno != EWOULDBLOCK) /* ERROR */ else write(tcpsock, …) if ( (n=read(tcpsock, …)<0)) if (errno != EWOULDBLOCK) /* ERROR */ else write(STDOUT_FILENO, …) } Network Programming (TDC 561) Winter 2003 Page 18

The problem with nonblocking I/O § Using blocking I/O allows the Operating System to

The problem with nonblocking I/O § Using blocking I/O allows the Operating System to put the process to sleep when nothing is happening (no input). Once input arrives the OS will wake up the process and read() (or write() … ) will return. § With nonblocking I/O the process will “busy-wait”, using inefficiently the CPU time Network Programming (TDC 561) Winter 2003 Page 19

Using alarms § Time-out handling with alarms signal(SIGALRM, sig_alrm); alarm(MAX_TIME); read(STDIN_FILENO, …); . .

Using alarms § Time-out handling with alarms signal(SIGALRM, sig_alrm); alarm(MAX_TIME); read(STDIN_FILENO, …); . . . signal(SIGALRM, sig_alrm); alarm(MAX_TIME); read(tcpsock, …); . . . § Issues: – How to assess the impact on response time ? – How to choose the value for MAX_TIME? Network Programming (TDC 561) Winter 2003 Page 20

Handling Timeout when calling recvfrom() Network Programming Aspects: § Nondeterministic delay, when calling recvfrom()

Handling Timeout when calling recvfrom() Network Programming Aspects: § Nondeterministic delay, when calling recvfrom() can be limited by generating an alarm signal after a specified period of time (even if there is no incoming datagram. ) § We can do this by using SIGALRM and wrapping each call to recvfrom() with a call to alarm() Network Programming (TDC 561) Winter 2003 Page 21

Handling Timeout when calling recvfrom() signal(SIGALRM, sig_alrm); alarm(max_time_to_wait); if (recvfrom(…)<0) if (errno==EINTR) /* timed

Handling Timeout when calling recvfrom() signal(SIGALRM, sig_alrm); alarm(max_time_to_wait); if (recvfrom(…)<0) if (errno==EINTR) /* timed out */ else /* some other error */ else /* no error or time out - turn off alarm */ alarm(0); Network Programming (TDC 561) Winter 2003 Page 22

select() § The select() system call allows us to use blocking I/O on a

select() § The select() system call allows us to use blocking I/O on a set of descriptors (file, socket, …). § For example, we can ask select to notify us when data is available for reading on either STDIN or a TCP socket. Network Programming (TDC 561) Winter 2003 Page 23

select() int select( int maxfd, fd_set *readset, fd_set *writeset, fd_set *excepset, const struct timeval

select() int select( int maxfd, fd_set *readset, fd_set *writeset, fd_set *excepset, const struct timeval *timeout); § The select() system call provides a way for a single server to wait until a set of network connections has data available for reading § The advantage over fork() here is that no multiple processes are spawned § The downside is that the single server must handle state management on its own for all its new clients – Finite State Machine Client/Server Model Network Programming (TDC 561) Winter 2003 Page 24

select() #include <sys/time. h> int select( int maxfd, fd_set *readset, fd_set *writeset, fd_set *excepset,

select() #include <sys/time. h> int select( int maxfd, fd_set *readset, fd_set *writeset, fd_set *excepset, const struct timeval *timeout); maxfd: highest number assigned to a descriptor. readset: set of descriptors we want to read from. writeset: set of descriptors we want to write to. excepset: set of descriptors to watch for exceptions/errors. timeout: maximum time select should wait Network Programming (TDC 561) Winter 2003 Page 25

select() § select() will return if any of the descriptors in readset and writeset

select() § select() will return if any of the descriptors in readset and writeset of file descriptors are ready for reading or writing, respectively, or, if any of the descriptors in exceptset are in an error condition § The FD_SET(int fd, fd_set *set) function will add the file descriptor fd to the set § The FD_ISSET(int fd, fd_set *set) function will tell you if filedescriptor fd is in the modified set § select() returns the total number of descriptors in the modified sets § If a client closes a socket whose file descriptor is in one of your watched sets, select() will return, and your next recv() will return 0, indicating the socket has been closed Network Programming (TDC 561) Winter 2003 Page 26

Setting the timeval in select() § Setting the timeout to 0, select() times out

Setting the timeval in select() § Setting the timeout to 0, select() times out immediately § Setting the timeout to NULL, select() will never time out, and will block indefinitely until a file descriptor is modified § To ignore a particular file descriptor set, just set it to NULL in the call: select (max, &readfds, NULL, NULL); – Here we only care about reading, and we want to block indefinitely until we do have a file descriptor ready to be read Network Programming (TDC 561) Winter 2003 Page 27

struct timeval { long tv_sec; long tv_usec; } /* seconds */ /* microseconds */

struct timeval { long tv_sec; long tv_usec; } /* seconds */ /* microseconds */ struct timeval max = {1, 0}; Network Programming (TDC 561) Winter 2003 Page 28

fd_set § Implementation is not important § Operations to use with fd_set: void FD_ZERO(

fd_set § Implementation is not important § Operations to use with fd_set: void FD_ZERO( fd_set *fdset); void FD_SET( int fd, fd_set *fdset); void FD_CLR( int fd, fd_set *fdset); int FD_ISSET( int fd, fd_set *fdset); Network Programming (TDC 561) Winter 2003 Page 29

Using select() § Create fd_set § Clear the whole set with FD_ZERO § Add

Using select() § Create fd_set § Clear the whole set with FD_ZERO § Add each descriptor you want to watch using FD_SET. § Call select § when select returns, use FD_ISSET to see if I/O is possible on each descriptor. Network Programming (TDC 561) Winter 2003 Page 30

Other Unix API Timers, Errors Distributed Systems Frameworks (DS 520 -95 -103) DISC’ 99

Other Unix API Timers, Errors Distributed Systems Frameworks (DS 520 -95 -103) DISC’ 99

Standard C library functions § <time. h> - declares set of functions for system

Standard C library functions § <time. h> - declares set of functions for system clock query time - #sec since 01/01/70 (UNIX birth) ctime - current local time localtime gmtime asctime mktime clock - (ANSI C) , #microsec since the process first called clock Network Programming (TDC 561) Winter 2003 Page 32

Example: <time. h> // evaluate process execution time --- C++ #include <iostream. h> #include

Example: <time. h> // evaluate process execution time --- C++ #include <iostream. h> #include <time. h> main() { time_t tick = CLOCKS_PER_SECOND; clock_t start_time = clock(); // start timer /* process code here */ clock_t duration = clock() - start_time; cout <<“Duration: ”<<(duration/tick)<<endl; } Network Programming (TDC 561) Winter 2003 Page 33