240 likes | 366 Views
010990001 - Tietoliikennetekniikan jatko-opintokurssi 2. Unix Network Programming Sockets Networking API Chapter 6 - I/O Multiplexing: the select and poll functions. I/O-tyypit. Kun asiakasohjelman pitää hoitaa useita syötteitä ja tulostuksia, jonkinlaista kanavointia tulisi käyttää niissä
E N D
010990001 - Tietoliikennetekniikan jatko-opintokurssi 2 Unix Network ProgrammingSockets Networking API Chapter 6 - I/O Multiplexing: theselect and poll functions
I/O-tyypit • Kun asiakasohjelman pitää hoitaa useita syötteitä ja tulostuksia, jonkinlaista kanavointia tulisi käyttää niissä • Unix-järjestelmässä 5 eri I/O-mallia: • blocking I/O • nonblocking I/O • I/O multiplexing (select, poll) • signal driven I/O (SIGIO) • asynchronous I/O (POSIX aio_ -funktiot)
Blocking I/O • Yleisin malli, oletuksena kaikki socketit ovat blokkaavia
Nonblocking I/O • Kun socket on asetettu nonblocking-tilaan, kernel palauttaa virheen, mikäli socketia käyttävä pyyntö ei onnistu välittömästi
I/O Multiplexing • I/O multiplexing -mallissa käytetään select- ja/tai poll-funktioita • blocking I/O -mallissa lukittuvan read/write/connect -kutsun sijasta select on se lukittuva funktio, mutta se odottaa useiden syötteiden tapahtumia • Yhtä syötettä käyttäessä huonompi vaihtoehto kuin tavallinen blocking I/O
Signal-Driven I/O • Kernel välittää SIGIO-signaalin, kun I/O-operaatio voidaan aloittaa
Asynchronous I/O • POSIX:ssa määritelty aio_-alkuisia funktioita, mutta tuki on aika rajoittunutta • aio_ -kutsun (esim. aio_read) yhteydessä kerrotaan kernelille signaali, joka sen tulee palauttaa, kun I/O-operaatio on valmis (vrt. signal-driven) • Funktio palaa välittömästi, ja prosessi jatkaa suoritustaan sillä aikaa. Kun määritelty signaali tulee kerneliltä, luetaan syötteestä
I/O-mallien vertailu wait for data copydata from kernel to user
select-funktio • select-kutsulla voidaan seurata, milloin • kuvaaja (fd) on luettavissa • kuvaaja on kirjoitettavissa • kuvaajan kohteessa tapahtuu jokin poikkeus • Eri joukot luettavuus-,kirjoitettavuus- ja poikkeustarkastuksille #include <sys/select.h> #include <sys/time.h> int select (int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
select-funktio • timeval-rakenteessa 2 komponenttia, sekunnit ja mikrosekunnit struct timeval { long tv_sec; /* seconds. */ long tv_usec; /* microseconds */ }; • Odotusajassa 3 vaihtoehtoa • odottaa ikuisesti (timeval *timeout = NULL) • odottaa tietyn aikaa (asetetaan timeval) • palaa välittömästi (timeout.tv_sec = 0, timeout.tv_usec = 0)
select-funktio • Luku-, kirjoitus- ja poikkeusjoukkoja voidaan käsitellä 4 makrolla: void FD_ZERO (fd_set *readset); void FD_SET (int fd, fd_set *readset); void FD_CLR (int fd, fd_set *readset); int FD_ISSET (int fd, fd_set *readset); • Ensimmäinen nollaa joukon, toinen lisää sinne yhden kuvaajan, kolmas poistaa ja neljäs tarkistaa, sisältyykö kuvaaja tiettyyn joukkoon
select-funktio • select-funktion ensimmäinen argumentti maxfdp1 on (joukkojen suurin fd) + 1 (huom. ei kuvaajien määrä + 1)
select-funktio • valmiusehdot lukujoukolle, eli milloin select-funktio palaa: • dataa on luettavissa enemmän kuin ”low-water mark”, oletuksena low-water mark on 1 • lukupuoli on suljettu (esim. TCP:ssä saatu FIN), lukuoperaatio palauttaa 0 • kuuntelevassa socketissa valmiita yhteyksiä • virhe odotettavissa, lukuoperaatio palauttaa -1 ja err_no :n arvo asetetaan
select-funktio • valmiusehdot kirjoitusjoukolle: • lähetysbufferissa dataa enemmän kuin ”low-water mark” ja socket a) yhdistetty b) ei tarvitse yhdistämistä (esim. UDP) • kirjoituspuoli suljettu, kirjoitusoperaatio luo SIGPIPE -signaalin • non-blocking connect-funktiota käyttävä yhteys on valmis tai connect epäonnistunut • socket-virhe odotettavissa, kirjoitusoperaatio palauttaa -1 ja err_no-arvo asetetaan
void str_cli(FILE *fp, int sockfd) { int maxfdp1; fd_set rset; char sendline[MAXLINE], recvline[MAXLINE]; FD_ZERO(&rset); for ( ; ; ) { FD_SET(fileno(fp), &rset); FD_SET(sockfd, &rset); maxfdp1 = max(fileno(fp), sockfd) + 1; Select(maxfdp1, &rset, NULL, NULL, NULL); if (FD_ISSET(sockfd, &rset)) { /* socket is readable */ if (Readline(sockfd, recvline, MAXLINE) == 0) err_quit("str_cli: server terminated prematurely"); Fputs(recvline, stdout); } if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */ if (Fgets(sendline, MAXLINE, fp) == NULL) return; /* all done */ Writen(sockfd, sendline, strlen(sendline)); } }}
shutdown-funktio • Batch-mode voi aiheuttaa ongelmia, jos funktio palaa ja fd suljetaan liian aikaisin • ratkaisu sulkemalla puolet TCP-yhteydestä, mutta pitämällä socketin fd yhä luettavana • Tämä voidaan tehdä shutdown-funktiolla int shutdown (int sockfd, int howto); • howto voi olla SHUT_RD, SHUT_WR, SHUT_RDWR
void str_cli(FILE *fp, int sockfd) { int maxfdp1, stdineof; fd_set rset; char buf[MAXLINE]; int n; stdineof = 0; FD_ZERO(&rset); for ( ; ; ) { if (stdineof == 0) FD_SET(fileno(fp), &rset); FD_SET(sockfd, &rset); maxfdp1 = max(fileno(fp), sockfd) + 1; Select(maxfdp1, &rset, NULL, NULL, NULL); if (FD_ISSET(sockfd, &rset)) { if ( (n = Read(sockfd, buf, MAXLINE)) == 0) { if (stdineof == 1) return; else err_quit("str_cli: server terminated prematurely"); } Write(fileno(stdout), buf, n); } if (FD_ISSET(fileno(fp), &rset)) { if ( (n = Read(fileno(fp), buf, MAXLINE)) == 0) { stdineof = 1; Shutdown(sockfd, SHUT_WR); FD_CLR(fileno(fp), &rset); continue; } Writen(sockfd, buf, n); } } }
pselect-funktio • int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); • 2 muutosta select-funktioon verrattuna • Käyttää timespec-rakennetta timeval:n sijasta, toisena jäsenenä nanosekunnit • Signaalimaski-osoitin, jolla • Käsitellään tarkemmin myöhemmin (kappaleessa 20)
poll-funktio int poll(struct pollfd *fdarray, unsigned int nfds, int timeout); struct pollfd { int fd; short events; short revents; }; • Poll-funktiolla voidaan määritellä halutut tapahtumat, joita odotetaan kuvaajasta (vain stream-tyyppiset inputit)