08 io multiplexing
TRANSCRIPT
-
7/31/2019 08 Io Multiplexing
1/32
-
7/31/2019 08 Io Multiplexing
2/32
ApplicationsforI/OMultiplexing
Clienthandlingmultipledescriptorse.g.theTCPechoclient
e.g.webclient
Serverhandlinglistenting,connectedsockets
,
Serverhandlingmultipleservices(xinetd)
3
I/OModels
BlockingI/O
Nonblocking I/O
,
SignaldrivenI/O(SIGIO)
AsynchronousI/O
4
-
7/31/2019 08 Io Multiplexing
3/32
BlockingI/OModel
Allexamplesseensofar
5
Nonblocking I/OModel
Dontputprocesstosleep
Returnerror(EWOULDBLOCK)instead
Needtocheckperiodically(polling) WasteofCPU
6
-
7/31/2019 08 Io Multiplexing
4/32
I/OMultiplexing
Blockinselectorpoll,notinactualI/Ocall
7
SignalDrivenI/OModel
InstallhandlerforSIGIO(signal,sigaction)
,
8
-
7/31/2019 08 Io Multiplexing
5/32
AsynchronousI/O
Similartosignaldrivenexcept
Notified after data is read in buffer
POSIXspec,stillnotwidelysupported
9
Comparison
10
-
7/31/2019 08 Io Multiplexing
6/32
select Function
#include
#include
int select(int maxfdp1, 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 */
long tv_usec; /* microseconds */
};
11
select Function
Waitforanyormultipleevents
Returnwhenoneormoreoccurortimeout
,
anyofdescriptors{1,4,5}isreadyforreading
anyofdescriptors{2,7}isreadyforwriting
an ofdescri tors 1 4 haveexce tion endin
10.2secondshaveelapsed
12
-
7/31/2019 08 Io Multiplexing
7/32
select Function
maxfdp1numberofdescriptorstobetested
maximum descri tor number + 1
FD_SETSIZE constantdefinedin
numberofdescriptorsinfd_set type
often1024,fewprogramsusethatmany maxfdp1isspecifiedforefficiency
13
readset,writeset,exceptset
Valueresultarguments
Oncalling,specifydescriptorsofinterest
,
14
-
7/31/2019 08 Io Multiplexing
8/32
-
7/31/2019 08 Io Multiplexing
9/32
SpecifyingDescriptorValues
fd_set rset;
_
FD_SET(1, &rset); /* turn on bit for fd 1 */
FD_SET(4, &rset); /* turn on bit for fd 4 */
* *_ ,
17
ReadyforReadingConditions
Bytesinsocketreceivebuffer>lowwatermark
defaultis1forTCP,UDPsocket
can be set with SO RCVLOWAT _
readwillnotblock(return>0)
ea a o t econnect onc ose
TCPconnectionreceivedFIN
read willnotblock(return0)
18
-
7/31/2019 08 Io Multiplexing
10/32
ReadyforReadingConditions
Listeningsocket:completedconnections>0accept willnotblock
read willnotblock(return 1)
errno issettospeci iccondition
19
ReadyforWritingConditions
Availablespaceinsendbuffer>lowwatermark
socketconnected(TCP)ornotrequireconn (UDP)
can be set with SO SNDLOWAT _
defaultto2048forTCP,UDP
r te a o connect onc ose
writeoperationwill generateSIGPIPE (errno)
20
-
7/31/2019 08 Io Multiplexing
11/32
ReadyforWritingConditions
Nonblocking socketconnectfunctioncompletedorfailed
write willnotblock(return 1)
errno issettospecificcondition
21
DescriptorConditionsSummary
Condition Readable? Writable?
Read halfoftheconnectionclosedNewconnectionreadyforlisteningsocket
Writehalfoftheconnectionclosed
Nonblocking connect() completedorfailed
Pendingerror
22
-
7/31/2019 08 Io Multiplexing
12/32
TCPEchoClientusingselect
tcpechosel1_cli.c
23
TCPEchoClientusingselect
str_cli() rewrittenusingselect
Blockedinselect insteadoffgets
Notifiedassoonasserverterminates
Onlyneedonedescriptorsetfor readability
wr ese an excep onse
24
-
7/31/2019 08 Io Multiplexing
13/32
ConditionsHandledusingselect
PeerTCP(server)senddataread returns>0
read returns0(EOF)
PeerTCPsendRST(crashed)
read returns 1errno =specificerror
25
ProblemwithBatchInput
Previouscodeworksokforinteractiveinput
Forbatchinput(e.g.redirectedfromfile)
atEOF,willreturntomain,exit
becauseofspeed,willnotreceiveserverresponse
Needtoclosehalfconnection write
leavereadopentoreceiveserverresponse
26
-
7/31/2019 08 Io Multiplexing
14/32
Limitationsofclose Function
Onlyclosessocketifrefcountreaches0sometimesweneedtoclosesocketregardless
sometimeswewanttocloseonedirectiononly
asencounteredinpreviousexample
27
shutdown Function
#include
,Returns: 0 if OK, 1 on error
howto Value Action
SHUT_RD readhalfof connectionclosed
nomore a acan erece ve
anydataonreceivebufferisdiscarded
SHUT_WR writehalfofconnectionclosed
nomoredatacanbesent
any datacurrentlyinsentbufferwillbesentfollowedbyTCP
connectionterminationsequence
SHUT_RDWR combines bothactionsabove
28
-
7/31/2019 08 Io Multiplexing
15/32
-
7/31/2019 08 Io Multiplexing
16/32
TCPEchoServerusingselect
tcpechosel1_srv.c
31
TCPEchoServerusingselect
Onlyusereadfd_set
Assumeserverstartedinforeground
, ,
listeningsocketwillusefd =3
Maintainarrayof
clientfds
initiallyall= 1
32
-
7/31/2019 08 Io Multiplexing
17/32
Handlingselect
Newconnectioncallaccept,updatedatastructuresandarrays
normaldata:echoback
FIN(connectionclosing):close,updatedata
RST(readerror):close,updatedata,reporterror
33
poll Function
#include
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; /* descriptor to check */
short events; /* events of interest on fd */
short revents; /* events that occurred on fd */
;
34
-
7/31/2019 08 Io Multiplexing
18/32
poll Function
Similarfunctionalitytoselect MoreinfoonSTREAMdevices(TCP)
fd:descriptorstobepolled
events:conditionstobechecked
revents:conditionsactuall occurred
Moresystemssupportselect thanpoll
35
InputeventsandReturnedrevents
Constant Inputtoevents?
Resultfromrevents?
Description
POLLINPOLLRDNORM
POLLRDBAND
NormalorprioritydatacanbereadNormaldatacanberead
Priorit band data can be read
POLLPRI
Highprioritydatacanberead
POLLOUT Normaldatacanbewritten
POLLWRBAND
Prioritybanddatacanbewritten
POLLERR Errorhasoccurred
POLLNVAL
angup asoccurre
Descriptor isnotanopenfile
36
-
7/31/2019 08 Io Multiplexing
19/32
TCPEchoServerusingpoll
tcpechopoll1_srv.c
37
AdditionalReferences
select
ttp: opengroup.org on inepu s 007908775 xs seect.html
p: ee .us gu e gne ou pu m mu page advanced.html#select
http://opengroup.org/onlinepubs/007908799/xsh/pol.
http://beej.us/guide/bgnet/output/html/multipage/p
38
-
7/31/2019 08 Io Multiplexing
20/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel1_cli.c Page 1 of 2
/* TCP echo client using selectworks good only for interactive inputcannot handle batch input redirected from another file
*/#include /* printf, fgets, fputs and standard i/o*/#include /* socket, bind, listen, accept, socklen_t */#include /* sockaddr_in, inet_ntop */
#include /* memset, strlen */#include /* exit */#include /* close, read */#include /* select */
#define SRV_PORT 5105 /* default port number */#define LISTEN_ENQ 5 /* for listen backlog */#define MAX_SEND_BUF 256#define MAX_RECV_BUF MAX_SEND_BUF
intstr_cli(FILE*,
int); /* prototype for function str_cli */
int main(int argc, char* argv[]){int sock_fd; /* client socket */struct sockaddr_in srv_addr; /* server address structure */
if (argc < 2) { /* user entered no arguments */printf("usage: %s \n", argv[0]); /* arg[0] is prog name*/
return -1;}
/* create a client socket */sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);srv_addr.sin_port = htons(SRV_PORT);srv_addr.sin_family = AF_INET;/* convert command line argument to numeric IP */if ( inet_pton(AF_INET, argv[1], &(srv_addr.sin_addr)) < 1 ){printf("Invalid IP address\n");return -1;
}
if( connect(sock_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) < 0 ){perror("connect error"); return -1;
}/* run the client using standard input */if (str_cli(stdin, sock_fd) < 0 )exit(-1);
else
exit(0);}
int str_cli(FILE* fp, int sock_fd){char recv_str[MAX_RECV_BUF]; /* buffer to hold received data */char send_str[MAX_SEND_BUF]; /* buffer to hold data to be sent */
-
7/31/2019 08 Io Multiplexing
21/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel1_cli.c Page 2 of 2
fd_set read_set; /* only read (from input or from socket) */int fp_no, /* file descriptor number of fp */
max_fd; /* maximum file descriptor */ssize_t rcvd_bytes, sent_bytes;
fp_no = fileno(fp);FD_ZERO(&read_set); /* initialize read_set to zero */
for(;;){FD_SET(fp_no, &read_set); /* set bit corresponding to fp */FD_SET(sock_fd, &read_set); /* set bit corresponding to sock_fd */max_fd = ( (fp_no > sock_fd) ? fp_no : sock_fd );
select(max_fd+1, &read_set, NULL, NULL, NULL);
if (FD_ISSET(sock_fd, &read_set)) /* socket is readable */
{ memset(recv_str, 0, MAX_RECV_BUF); // clear recv_str /* read back from socket into recv_str */ if ( (rcvd_bytes = read(sock_fd, recv_str, MAX_RECV_BUF)) < 0 ) {
perror("read error"); return -1;}
if (rcvd_bytes == 0) { /* server has been shutdown */printf("Server terminated prematurely\n"); return -1;
}/* write received line to standard output */
fputs(recv_str, stdout);} // if
if (FD_ISSET(fp_no, &read_set)) /* fp (stdin) is readable */{ /* get input from file fp into send_str buffer */
/* fgets returns NULL when EOF, EOL or MAX_SEND_BUF reached */if( fgets(send_str,MAX_SEND_BUF, fp) == NULL ){puts("EOF");
return0; /* reached EOF ^D */
}
/* else, write send_str contents to socket */ if ( (sent_bytes = write(sock_fd, send_str, strlen(send_str))) < 0 ) {
perror("write error"); return -1;}
} //if
} // forreturn0;
}
-
7/31/2019 08 Io Multiplexing
22/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel2_cli.c Page 1 of 3
/* TCP echo client using selectcan handle batch input redirected from another file
*/
#include /* printf, fgets, fputs and standard i/o*/#include /* socket, bind, listen, accept, socklen_t */#include /* sockaddr_in, inet_ntop */
#include /* memset, strlen */#include /* exit */#include /* close, read */#include /* select */
#define SRV_PORT 5105 /* default port number */#define LISTEN_ENQ 5 /* for listen backlog */#define MAX_SEND_BUF 256#define MAX_RECV_BUF MAX_SEND_BUF
intstr_cli(FILE*,
int); /* prototype for function str_cli */
int main(int argc, char* argv[]){int sock_fd; /* client socket */struct sockaddr_in srv_addr; /* server address structure */
if (argc < 2) { /* user entered no arguments */printf("usage: %s \n", argv[0]); /* arg[0] is prog name*/
return -1;}
/* create a client socket */sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);srv_addr.sin_port = htons(SRV_PORT);srv_addr.sin_family = AF_INET;/* convert command line argument to numeric IP */if ( inet_pton(AF_INET, argv[1], &(srv_addr.sin_addr)) < 1 ){printf("Invalid IP address\n");return -1;
}
if( connect(sock_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) < 0 ){perror("connect error"); return -1;
}/* run the client using standard input */if (str_cli(stdin, sock_fd) < 0 )exit(-1);
else
exit(0);}
int str_cli(FILE* fp, int sock_fd){char recv_str[MAX_RECV_BUF]; /* buffer to hold received data */char send_str[MAX_SEND_BUF]; /* buffer to hold data to be sent */
-
7/31/2019 08 Io Multiplexing
23/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel2_cli.c Page 2 of 3
fd_set read_set; /* only read (from input or from socket) */int fp_no, /* file descriptor number of fp */
max_fd; /* maximum file descriptor */ssize_t rcvd_bytes, sent_bytes, read_bytes;int stdin_eof; /* flag indicate eof from stdin */
fp_no = fileno(fp);
stdin_eof = 0;FD_ZERO(&read_set); /* initialize read_set to zero */
for(;;){if(stdin_eof == 0)FD_SET(fp_no, &read_set); /* set bit corresponding to fp */
FD_SET(sock_fd, &read_set); /* set bit corresponding to sock_fd */max_fd = ( (fp_no > sock_fd) ? fp_no : sock_fd );
select(max_fd+1, &read_set, NULL, NULL, NULL);
if (FD_ISSET(sock_fd, &read_set)) /* socket is readable */{memset(recv_str, 0, MAX_RECV_BUF); // clear recv_str
/* read back from socket into recv_str */ if ( (rcvd_bytes = read(sock_fd, recv_str, MAX_RECV_BUF)) < 0 ) {
perror("read error"); return -1;}
if (rcvd_bytes == 0)
{ if (stdin_eof == 1) return0; /* normal termination */ else
{ /* server has been shutdown */printf("Server terminated prematurely\n");
return -1;}
}/* write received line to standard output */fputs(recv_str, stdout);
} // if
if (FD_ISSET(fp_no, &read_set)) /* fp (stdin) is readable */{ /* read input from file fp into send_str buffer */ if ( (read_bytes = read(fp_no, send_str, MAX_SEND_BUF)) == 0){stdin_eof = 1;shutdown(sock_fd, SHUT_WR); /* send FIN, can still recv */FD_CLR(fp_no, &read_set);puts("EOF");
continue
;}
/* else, write send_str contents to socket */ if ( (sent_bytes = write(sock_fd, send_str, read_bytes)) < 0 ) {
-
7/31/2019 08 Io Multiplexing
24/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel2_cli.c Page 3 of 3
perror("write error"); return -1;}
} //if} // for
return0;}
-
7/31/2019 08 Io Multiplexing
25/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel1_srv.c Page 1 of 3
/*TCP echo server using selectbased on example in figure 6.21 in the textbook*/
#include #include
#include #include /* memset */#include /* close, read, write */#include /* select */
#define SRV_PORT 5105 /* default port number */#define LISTEN_ENQ 5 /* for listen backlog */#define MAX_RECV_BUF 256#define MAX_CLIENTS FD_SETSIZE
intmain(
intargc,
char* argv[]){
int listen_fd, conn_fd,clients [MAX_CLIENTS], /* array of client sockets */client_fd, /* current client being serviced */max_fd, /* maximum file descriptor */i, /* index to use with clients[] array */max_i, /* max index of connected client */n_ready; /* number of ready fds returned from select() */
fd_set read_set, /* readable file descriptors to use with select() */all_set; /* all file descriptors, to prepare read_set */
char recv_str[MAX_RECV_BUF];ssize_t rcvd_bytes, sent_bytes;struct sockaddr_in srv_addr, cli_addr;socklen_t cli_len;
/* start */if ( (listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {perror("listen error"); return -1;
}memset(&srv_addr, 0, sizeof(srv_addr));memset(&cli_addr, 0, sizeof(cli_addr));
srv_addr.sin_family = AF_INET;srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);srv_addr.sin_port = htons(SRV_PORT);
if ( bind(listen_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr))< 0 ){perror("bind error"); return -1;
}if ( listen(listen_fd, LISTEN_ENQ) < 0 ) {perror("listen error"); return -1;
}
max_fd = listen_fd; /* initially, maximum fd is listening socket fd */max_i = -1; /* no connected clients yet */
for(i=0; i < MAX_CLIENTS; i++)
-
7/31/2019 08 Io Multiplexing
26/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel1_srv.c Page 2 of 3
clients[i] = -1; /* -1 indicates available entry */
FD_ZERO(&all_set); /* clear all_set */FD_SET(listen_fd, &all_set); /* set entry for listen_fd */
for(;;) /* main loop */{
read_set = all_set; /* copy all_set to read_set */
/* block in select until a fd is ready, no timeout */n_ready = select(max_fd + 1, &read_set, NULL, NULL, NULL);
/* once select returns, check which fds are ready */
if (FD_ISSET(listen_fd, &read_set)) /* new client connection */{cli_len = sizeof(cli_addr);
if
( (conn_fd = accept(listen_fd, (struct
sockaddr*) &cli_addr,&cli_len) ) < 0 ) {perror("accept error");
continue; /* go back to main loop */}
for (i=0; i < MAX_CLIENTS ; i++)if (clients[i] < 0){clients[i] = conn_fd; /* assign conn_fd to first available */break; /* slot in clients array */
}
if ( i == MAX_CLIENTS ){fputs("too many clients", stderr);close (conn_fd); /* disconnect this client */continue; /* go back to main loop */
}
FD_SET(conn_fd, &all_set); /* add new fd to next loop select */
if( conn_fd > max_fd) max_fd = conn_fd; /* update max_fd */if (i > max_i) max_i = i; /* update max_i */
if (--n_ready
-
7/31/2019 08 Io Multiplexing
27/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel1_srv.c Page 3 of 3
if (rcvd_bytes
-
7/31/2019 08 Io Multiplexing
28/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel2_srv.c Page 1 of 2
/*TCP echo server using select (more compact)based on example from Beej's tutorial to network programming*/
#include #include
#include #include /* memset */#include /* close, read, write */#include /* select */
#define SRV_PORT 5105 /* default port number */#define LISTEN_ENQ 5 /* for listen backlog */#define MAX_RECV_BUF 256
int main(int argc, char* argv[])
{ int listen_fd, conn_fd,max_fd, /* maximum file descriptor */i; /* index */
fd_set read_set, /* readable file descriptors to use with select() */all_set; /* all file descriptors, to prepare read_set */
char recv_str[MAX_RECV_BUF];ssize_t rcvd_bytes, sent_bytes;struct sockaddr_in srv_addr, cli_addr;socklen_t cli_len;
/* start */if ( (listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {perror("listen error"); return -1;
}memset(&srv_addr, 0, sizeof(srv_addr));memset(&cli_addr, 0, sizeof(cli_addr));srv_addr.sin_family = AF_INET;srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);srv_addr.sin_port = htons(SRV_PORT);
if ( bind(listen_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr))< 0 ){
perror("bind error"); return -1;}if ( listen(listen_fd, LISTEN_ENQ) < 0 ) {perror("listen error"); return -1;
}
max_fd = listen_fd; /* initially, maximum fd is listening socket fd */FD_ZERO(&all_set); /* clear all_set */FD_SET(listen_fd, &all_set); /* set entry for listen_fd */
for(;;) /* main loop */{read_set = all_set; /* copy all_set to read_set */
/* block in select until a fds is ready, no timeout */
-
7/31/2019 08 Io Multiplexing
29/32
File: /home/mostafa/netprog/tcpsockex/tcpechosel2_srv.c Page 2 of 2
if( select(max_fd + 1, &read_set, NULL, NULL, NULL) < 0 ) {perror("select error"); return -1;
}
/* once select returns, check which fds is ready */for (i=0; i max_fd)max_fd = conn_fd; /* update max_fd */
}}//end if new connection
else/* it is data for client */{rcvd_bytes = read(i, recv_str, MAX_RECV_BUF);
if (rcvd_bytes
-
7/31/2019 08 Io Multiplexing
30/32
File: /home/mostafa/netprog/tcpsockex/tcpechopoll1_srv.c Page 1 of 3
/*TCP echo server using pollbased on example in figure 6.25 in the textbook*/
#include #include
#include #include /* memset */#include /* close, read, write */#include /* poll */
#define SRV_PORT 5105 /* default port number */#define LISTEN_ENQ 5 /* for listen backlog */#define MAX_RECV_BUF 256#define MAX_CLIENTS 256
intmain(
intargc,
char* argv[]){
int listen_fd, conn_fd, client_fd, i, max_i, n_ready;char recv_str[MAX_RECV_BUF];ssize_t rcvd_bytes, sent_bytes;struct sockaddr_in srv_addr, cli_addr;socklen_t cli_len;struct pollfd clients[MAX_CLIENTS]; /* array of pollfd structures */
/* start */if ( (listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {
perror("listen error"); return -1;}memset(&srv_addr, 0, sizeof(srv_addr));memset(&cli_addr, 0, sizeof(cli_addr));srv_addr.sin_family = AF_INET;srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);srv_addr.sin_port = htons(SRV_PORT);
if ( bind(listen_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr))< 0 ){perror("bind error"); return -1;
}
if ( listen(listen_fd, LISTEN_ENQ) < 0 ) {perror("listen error"); return -1;
}
clients[0].fd = listen_fd; /* first element is listening socket */clients[0].events = POLLIN; /* poll for input data read */
for (i=1; i< MAX_CLIENTS; i++)clients[i].fd = -1; /* initialize the rest of the array */
max_i = 0; /* max index of the array */
for(;;) /* main loop*/{n_ready = poll(clients, max_i + 1, -1); /* -1 means no timeout */if (n_ready < 0) {
-
7/31/2019 08 Io Multiplexing
31/32
File: /home/mostafa/netprog/tcpsockex/tcpechopoll1_srv.c Page 2 of 3
perror("poll"); return -1;}
if (clients[0].revents & POLLIN){/* listening socket data, i.e. new connection */cli_len = sizeof(cli_addr);
if ( (conn_fd = accept(listen_fd, (struct sockaddr*) &cli_addr,
&cli_len) ) < 0 ) {perror("accept error");
continue; /* go back to main loop */}
for (i=1; i < MAX_CLIENTS ; i++)if (clients[i].fd < 0){clients[i].fd = conn_fd; /* assign conn_fd to first available */break; /* slot in clients array */
}
if ( i == MAX_CLIENTS ){fputs("too many clients", stderr);close (conn_fd); /* disconnect this client */continue; /* go back to main loop */
}
clients[i].events = POLLIN; /* add events for poll to new client */
if (i > max_i) max_i = i; /* update max_i */
if (--n_ready
-
7/31/2019 08 Io Multiplexing
32/32
File: /home/mostafa/netprog/tcpsockex/tcpechopoll1_srv.c Page 3 of 3
{close(client_fd);clients[i].fd = -1;perror("write error");
}}
if (--n_ready