08 Io Multiplexing

Embed Size (px)

Citation preview

  • 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