IO Multiplexing n Capability of tell the kernel

I/O Multiplexing n Capability of tell the kernel that wants to be notified when one or more I/O conditions are ready. For example, I/O data is available. n Select e poll

I/O Multiplexing n n When a client is handling multiple descriptors, interactive input When TCP server handles listening sockets and other connected sockets When the servers accepts requests from both TCP and UDP. When a server handles multiple service or multiple protocols

I/O n n n Blocking I/O Non-blocking I/O multiplexing Signal driven I/O Asynchronous I/O

I/O Operation n Two steps: 1. 2. Waiting for data to be ready Copying the data from the kernel to the process

Blocking I/O

Nonblocking I/O n Does not put process into the sleep state n Returns code EWOULDBLOCK n Polling

Nonblocking I/O

Select

Signal driven I/O n Request the kernel to notify with the signal SEGIO when event occurs n Not non-blocking n Recvfrom or main loop

Signal driven I/O

Asynchronous I/O n Tells the kernel when start the operation n Kernell notifies when operation is completed including copy from the ketnel to the buffer

E/S assíncrona

I/O Type

select n Tell the kernel to wake up the process either when a set of events happen or when a timeout happens n The type of descriptor can be specified (reading, writing or exception)

select #include <sys/select. h> #include <sys/time. h> int select(int maxfdp 1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout); Returns: positive count of ready descriptors, 0 on timeout, – 1 on error struct timeval { long tv_sec; /* seconds */ a long tv_usec; /* microseconds */ };

select n Three Possibilities of wait: ¡ ¡ ¡ Wait until descriptor is ready for I/O– null pointer specifies the timeout value Wait up to a fixed amount of time Do not wait beyond the time specified in timeval structure

select n Two options for test of execution: ¡ ¡ Arrival of out-of band data The presenc of control status information to be read from master side pf pseudo terminal

select n n descriptor set (array of integers) – each bit corresponds to a signal Four macros: 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);

select n Select modifies the descriptor set of readset, writeset, excepetion (value-result arguments) n Set all bits and check at return

Descriptors ready Conditions for a descriptor to be ready for reading if one of the following conditions is true: n The number of bytes of data in the socket receive buffer is greater than or equal to the current size of the low-water mark for the socket receive buffer. The option SO_RCVLOWAT allows to set this parameter n The read-half of the connection is closed (TCP connecton received a FIN). A read operation on the socket will not block, returns zero

Descriptors ready n n The socket is a listening socket and the number of completed connections is nonzero. An accept on the listening socket will not block A socket error is pending. A read operation on the socket will not block and will return an error. These pending errors can be fetched and cleared by calling getsockopt

Descriptors ready Conditions for a descriptor to be ready for writing if one of the following conditions is true: n The number of bytes available space in the socket send buffer is greater than or equal to the current size of the low-water mark for the socket send buffer and either the socket is connected or it does not require a connections. The low-water marking can be set by using SO_SNDLOWAT n The write half of the connection is closed. A write operation will generate SIGPIPE

Descriptors ready n n n The write-half of the connection is closed. A write operation on the socket will generate a SIGPIPE A socket error is pending. A write operation will not block and will return an error. Calling getsockops for the SO_ERROR socket option will clear the error

Ready for select n A UDP socket is always writable since no connection is required n There is a limited number of descriptors per sockets

str_cli 1 #include "unp. h" 2 void 3 str_cli(FILE *fp, int sockfd) 4 { 5 char sendline[MAXLINE], recvline[MAXLINE]; 6 while (Fgets(sendline, MAXLINE, fp) != NULL) { 7 Writen(sockfd, sendline, strlen (sendline)); 8 if (Readline(sockfd, recvline, MAXLINE) == 0) 9 err_quit("str_cli: server terminated prematurely"); 10 Fputs(recvline, stdout); 11 } 12 }

str_cli

str_cli 1 #include "unp. h" 2 void 3 str_cli(FILE *fp, int sockfd) 4 { 5 int maxfdp 1; 6 fd_set rset; 7 char sendline[MAXLINE], recvline[MAXLINE]; 8 FD_ZERO(&rset); 9 for ( ; ; ) { 10 FD_SET(fileno(fp), &rset); 11 FD_SET(sockfd, &rset); 12 maxfdp 1 = max(fileno(fp), sockfd) + 1; 13 Select(maxfdp 1, &rset, NULL, NULL); 14 if (FD_ISSET(sockfd, &rset)) { /* socket is readable */ 15 if (Readline(sockfd, recvline, MAXLINE) == 0) 16 err_quit("str_cli: server terminated prematurely"); 17 Fputs(recvline, stdout); 18 } 19 if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */ 20 if (Fgets(sendline, MAXLINE, fp) == NULL) 21 return; /* all done */ 22 Writen(sockfd, sendline, strlen(sendline)); 23 } 24 } 25 }

str_cli n Function fileno converts a pointer to na I/O file into a pointer to descritors. Both select and poll work only on descriptors n Descriptors for writing and for exceptions are set null n Flow is driven by select and not by fget anymore

Stop and wait mode

Batch mode

Close Limitations of the close operation: n n n close decrements the descriptor’s reference count and closes the socket only if the count reaches; close terminates both directions of data transfer, reading and writing. shutdown send a FIN segment

shutdown

shutdown #include <sys/socket. h> int shutdown(int sockfd, int howto); Returns: 0 if OK, – 1 on error n shutdown howto: ¡ ¡ ¡ SHUT_RD – the read-half of the connection is closed; no more read data and socket receive buffer content is discarded. SHUT_WR – the write-half is closed. Any data currently in the socket send buffer will be sent , followed by TCP’s normal termination sequence SHUT_RDWR both read and write are closed.

str_cli (final version) 3 void str_cli(FILE *fp, int sockfd) 4 { 5 int maxfdp 1, stdineof; 6 fd_set rset; 7 char buf[MAXLINE]; 8 int n; 9 stdineof = 0; 10 FD_ZERO(&rset); 11 for ( ; ; ) { 12 if (stdineof == 0) 13 FD_SET(fileno(fp), &rset); 14 FD_SET(sockfd, &rset); 15 maxfdp 1 = max(fileno(fp), sockfd) + 1; 16 Select(maxfdp 1, &rset, NULL, NULL); 17 if (FD_ISSET(sockfd, &rset)) { /* socket is readable */ 18 if ( (n = Read(sockfd, buf, MAXLINE)) == 0) { 19 if (stdineof == 1) 20 return; /* normal termination */ 21 else 22 err_quit("str_cli: server terminated prematurely"); 23 } 24 Write(fileno(stdout), buf, n); 25 } 26 if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */ 27 if ( (n = Read(fileno(fp), buf, MAXLINE)) == 0) { 28 stdineof = 1; 29 Shutdown(sockfd, SHUT_WR); /* send FIN */ 30 FD_CLR(fileno(fp), &rset); 31 continue; 32 } 33 Writen(sockfd, buf, n); 34 } 35 } 36 }

TCP Echo server (1)

TCP Echo server (2)

TCP Echo server (3)

TCP echo server (4)

TCP echo server (5) 2 int 3 main(int argc, char **argv) 4 { 5 int i, maxfd, listenfd, connfd, sockfd; 6 int nready, client[FD_SETSIZE]; 7 ssize_t n; 8 fd_set rset, allset; 9 char buf[MAXLINE]; 10 socklen_t clilen; 11 struct sockaddr_in cliaddr, servaddr; 12 listenfd = Socket(AF_INET, SOCK_STREAM, 0); 13 bzero(&servaddr, sizeof(servaddr)); 14 servaddr. sin_family = AF_INET; 15 servaddr. sin_addr. s_addr = htonl(INADDR_ANY); 16 servaddr. sin_port = htons(SERV_PORT); 17 Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 18 Listen(listenfd, LISTENQ); 19 maxfd = listenfd; /* initialize */ 20 maxi = -1; /* index into client[] array */ 21 for (i = 0; i < FD_SETSIZE; i++) 22 client[i] = -1; /* -1 indicates available entry */ 23 FD_ZERO(&allset); 24 FD_SET(listenfd, &allset); . . .

TCP echo server. . . 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45. . . (6) for ( ; ; ) { rset = allset; /* structure assignment */ nready = Select(maxfd + 1, &rset, NULL, NULL); if (FD_ISSET(listenfd, &rset)) { /* new client conn */ clilen = sizeof(cliaddr); connfd = Accept(listenfd, (SA *) &cliaddr, &clilen); for (i = 0; i < FD_SETSIZE; i++) if (client[i] < 0) { client[i] = connfd; /* save descriptor */ break; } if (i == FD_SETSIZE) err_quit("too many clients"); FD_SET(connfd, &allset); /* add new descriptor to set */ if (connfd > maxfd) maxfd = connfd; /* for select */ if (i > maxi) maxi = i; /* max index in client[] array */ if (--nready <= 0) continue; /* no more readable descriptors */ }*/ if */

TCP echo server. . . 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 } 62 }/* (7) for (i = 0; i <= maxi; i++) { /* check all clients for data */ if ( (sockfd = client[i]) < 0) continue; if (FD_ISSET(sockfd, &rset)) { if ( (n = Read(sockfd, buf, MAXLINE)) == 0) { /* connection closed by client */ Close(sockfd); FD_CLR(sockfd, &allset); client[i] = -1; } else Writen(sockfd, buf, n); if (--nready <= 0) break; /* no more readable descriptors */ } } /* end for */ end main */

Denial of service n Client sends a byte and go into sleep mode, server becomes blocked A server that accepts request from multiple server can not block given a request of a single client n Potential solution: n 1. 2. 3. Use of non-blocking I/O Each client treated as individual thread of control Set timer to I/O operation

poll n Similar to select but provide additional information #include <poll. h> int poll (struct pollfd *fdarray, unsigned long nfds, int timeout); Returns: count of ready descriptors, 0 on timeout, – 1 on error struct pollfd { int fd; short events; short revents; }; /* descriptor to check */ /* events of interest on fd */ /* events that occurred on fd */

poll

poll n Three types of data: ¡ ¡ ¡ n n n Normal priority band High priority TCP and UDP data are considered normal TCP out-of-band is considered priority band New connection at listenning socket can be considered either as normal or as priority band

TCP echo server (with poll) (1) 1 #include "unp. h" 2 #include <limits. h> /* for OPEN_MAX */ 3 int 4 main(int argc, char **argv) 5 { 6 int i, maxi, listenfd, connfd, sockfd; 7 int nready; 8 ssize_t n; 9 char buf[MAXLINE]; 10 socklen_t clilen; 11 struct pollfd client[OPEN_MAX]; 12 struct sockaddr_in cliaddr, servaddr; 13 listenfd = Socket(AF_INET, SOCK_STREAM, 0); 14 bzero(&servaddr, sizeof(servaddr)); 15 servaddr. sin_family = AF_INET; 16 servaddr. sin_addr. s_addr = htonl(INADDR_ANY); 17 servaddr. sin_port = htons(SERV_PORT); 18 Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 19 Listen(listenfd, LISTENQ); 20 client[0]. fd = listenfd; 21 client[0]. events = POLLRDNORM; 22 for (i = 1; i < OPEN_MAX; i++) 23 client[i]. fd = -1; /* -1 indicates available entry */ 24 maxi = 0; /* max index into client[] array */

TCP echo server (withpoll). . . 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 }. . . (2) for ( ; ; ) { nready = Poll(client, maxi + 1, INFTIM); if (client[0]. revents & POLLRDNORM) { /* new client conn */ clilen = sizeof(cliaddr); connfd = Accept(listenfd, (SA *) &cliaddr, &clilen); for (i = 1; i < OPEN_MAX; i++) if (client[i]. fd < 0) { client[i]. fd = connfd; /* save descriptor */ break; } if (i == OPEN_MAX) err_quit("too many clients"); client[i]. events = POLLRDNORM; if (i > maxi) maxi = i; /* max index in client[] array */ if (--nready <= 0) continue; /* no more readable descriptors */

TCP echo server (with poll) (3) 43 for (i = 1; i <= maxi; i++) { /* check all clients for data */ 44 if ( (sockfd = client[i]. fd) < 0) 45 continue; 46 if (client[i]. revents & (POLLRDNORM | POLLERR)) { 47 if ( (n = read(sockfd, buf, MAXLINE)) < 0) { 48 if (errno == ECONNRESET) { 49 /* connection reset by client */ 50 Close(sockfd); 51 client[i]. fd = -1; 52 } else 53 err_sys("read error"); 54 } else if (n == 0) { 55 /* connection closed by client */ 56 Close(sockfd); 57 client[i]. fd = -1; 58 } else 59 Writen(sockfd, buf, n); 60 if (--nready <= 0) 61 break; /* no more readable descriptors */ 62 } 63 } 64 } 65 }
- Slides: 48