Z a aw a n so w a n e o p e ra cj e w e jś ci a / w y jś ci a
WitoldPaluszyński witold.paluszynski@pwr.edu.pl http://www.kcir.pwr.edu.pl/∼ witold/ Copyrightc 2002–2003WitoldPaluszyński Allrightsreserved. Niniejszydokumentzawieramateriałydowykładunatematzaawansowanychoperacji wejścia/wyjściawsystemieUnix.Jestonudostępnionypodwarunkiemwykorzystania wyłączniedowłasnych,prywatnychpotrzebimożebyćkopiowanywyłączniewcałości, razemzniniejsząstronątytułową.B lo k o w a n ie o p e ra cj i I/ O
Blokowanieoperacjiwejścia/wyjściaoznaczaoczekiwanienamożliwośćodczytania albozapisaniadanych.Przykładyblokowaniawejścia/wyjścia: •odczytzplikówurządzeń,gdyniemawnichjużdanych(potoki,terminale, gniazdka), •zapisdotychsamychurządzeń,jeślidaneniemogąbyćodrazuprzyjęte, •otwarcieplikublokujedomomentuspełnieniapewnychwarunków(np.otwarcie plikuterminaladochwilinawiązaniapołączeniaprzezmodem,otwarcieFIFOdo zapisugdyżadenprocesniemagootwartegodoodczytu,itp.), •operacjenaplikachzmandatoryrecordlocking, •iinne. Unix:zaawansowaneoperacjeI/O3N ie b lo k u ją ce w e jś ci e / w yj śc ie
BlokowanieoperacjiI/Omożnakontrolować,toznaczymożnatakskonfigurować operacjewejścia/wyjścia,bywsytuacjiktóranormalniespowodowałabyblokowanie, funkcjawróciłaodrazuzkodemwskazującymniemożnośćwykonaniaoperacji. •openzflagąO_NONBLOCK •fcntlnaotwartymdeskryptorzeztąsamąflagą Wtedypowrótzfunkcjiread/writenastępujezbłędemwskazującym,żeoperacjaby blokowała. UWAGA:możnazastosowaćstarąflagęO_NDELAY,wtedyfunkcjeread/write zwracają0,cojednakpokrywasięzsygnalizacjąEOF(SystemV). Unix:zaawansowaneoperacjeI/O4R ó w n o cz e sn e o p e ra cj e I/ O
Jakzorganizowaćoperacjewejścia/wyjścia,gdymamynp.jednocześniekilkaźródeł,z którychnadchodządane? Naprzykład,emulatorterminala,komunikującysięzjednejstronyzużytkownikiem,a zdrugiejzezdalnymsystemem: Możliwesąnastępującerozwiązania: •polling:nieblokującepróbyodczytunaprzemianzkolejnychdeskryptorów; wniektórychsystemachmożnateżużyćnagniazdkach: ioctl(fd,FIONREAD,&nread); •przełączanie(multiplexing):funkcjeselectipoll •asynchroniczneI/O:powiadamianieprocesuprzezjądro(przypomocysygnału)o gotowoścideskryptoradooperacjiI/O Unix:zaawansowaneoperacjeI/O5 Unix:zaawansowaneoperacjeI/O6I/ O m u lt ip le xi n g
TenmechanizmniejestobjętynormąPOSIX,jednakfunkcjaselect()istnieje wUnixachAT&TiBSDoddawnaijestdośćstandardowa.Funkcjapoll()je nowa,iwniektórychsystemachjestzaimplementowanaprzezselect. structtimeval{ time_ttv_sec;/*seconds*/ suseconds_ttv_usec;/*andmicroseconds*/ }; intselect(intnfds,fd_set*readfds,fd_set*writefds, fd_set*errorfds,structtimeval*timeout); Funkcjaselect()zwracaliczbędeskryptorówgotowychdooperacjiI/O.Pop wynikającymzupłynięciazadanegoczasufunkcjazerujewszystkiezbiorydeskry wsystemieV,leczpozostawiajeniezmienionewsystemieBSD.Tesystemyró inaczejlicządeskryptorygotowedoI/O(AT&Tliczyjewsensiemnogościowym BSDsumujearytmetycznielicznościwszystkichtrzechzbiorówdeskryptorów). Ponadto,niektóresystemywprzypadkugotowoścideskryptoraustawiająwstru timevalczaspozostałydowyczerpania(Linux). Unix:zaawansowaneoperacjeI/O Dotworzeniaodpowiednichzbiorówdeskryptorów,atakżesprawdzaniaotrzym wyników,istniejąmakra: voidFD_SET(intfd,fd_set*fdset); voidFD_CLR(intfd,fd_set*fdset); intFD_ISSET(intfd,fd_set*fdset); voidFD_ZERO(fd_set*fdset); Funkcjapollzapewniapodobnedziałanieleczinnyinterfaceprogramisty: structpollfd{ intfd;/*filedescriptor*/ shortevents;/*requestedevents*/ shortrevents;/*returnedevents*/ } intpoll(structpollfdfds[],nfds_tnfds,inttimeout); Tablicastrukturpollfdokreślawszystkiedeskryptoryizdarzenia,naktórech oczekiwać(czasokreślanyjesttuwmilisekundach).Wartośćzwracanazfunkcj liczbęgotowychdeskryptorów. Unix:zaawansowaneoperacjeI/OF u n k cj a s e l e c t — p rz yk ła d
#include<sys/types.h> #include<sys/time.h> #include<stdio.h> #include<fcntl.h> #include<sys/ioctl.h> #include<unistd.h> intmain(){ charbuffer[128]; intresult,nread; fd_setinputs,testfds; structtimevaltimeout; FD_ZERO(&inputs); FD_SET(0,&inputs); while(1){ testfds=inputs; timeout.tv_sec=2; timeout.tv_usec=500000; result=select(FD_SETSIZE,&testfds,(fd_set*)0, (fd_set*)0,&timeout); Unix:zaawansowaneoperacjeI/O9 switch(result){ case0: printf("timeout\n"); break; case-1: perror("select"); exit(1); default: if(FD_ISSET(0,&testfds)){ ioctl(0,FIONREAD,&nread); if(nread==0){ printf("keyboarddone\n"); exit(0); } nread=read(0,buffer,nread); buffer[nread]=0; printf("read%dfromkeyboard:%s",nread,buffer); } break; } } } Unix:zaawansowaneoperacjeI/O10F u n k cj a s e l e c t — in n y p rz yk ła d
#include<sys/types.h> #include<sys/socket.h> #include<stdio.h> #include<netinet/in.h> #include<sys/time.h> #include<sys/ioctl.h> #include<unistd.h> intmain(){ intserver_sockfd,client_sockfd; intserver_len,client_len; structsockaddr_inserver_address; intresult; fd_setreadfds,testfds; server_sockfd=socket(AF_INET,SOCK_STREAM,0); server_address.sin_family=AF_INET; server_address.sin_addr.s_addr=htonl(INADDR_ANY); server_address.sin_port=htons(9734); server_len=sizeof(server_address); bind(server_sockfd,(structsockaddr*)&server_address,server_len); listen(server_sockfd,5); Unix:zaawansowaneoperacjeI/O11 FD_ZERO(&readfds); FD_SET(server_sockfd,&readfds); while(1){ charch; intfd,nread; testfds=readfds; printf("serverwaiting\n"); result=select(FD_SETSIZE,&testfds,(fd_set*)0, (fd_set*)0,(structtimeval*)0); if(result<1){ perror("server5"); exit(1); } for(fd=0;fd<FD_SETSIZE;fd++){ if(FD_ISSET(fd,&testfds)){ if(fd==server_sockfd){ client client_sockfd=accept(server_sockfd,0,0); FD_SET(client_sockfd,&readfds); printf("addingclientonfd%d\n",client_sockfd); } Unix:zaawansowaneoperacjeI/O12else{ ioctl(fd,FIONREAD,&nread); if(nread==0){ close(fd); FD_CLR(fd,&readfds); printf("removingclientonfd%d\n",fd); } else{ read(fd,&ch,1); sleep(5); printf("servingclientonfd%d\n",fd); ch++; write(fd,&ch,1); } } } } } } Unix:zaawansowaneoperacjeI/O13 Unix:zaawansowaneoperacjeI/O14