vælg (Unix) - select (Unix)
select er et systemopkald og applikationsprogrammeringsinterface (API) i Unix -lignende og POSIX -kompatible operativsystemer til undersøgelse af status for filbeskrivelser for åbne input/output -kanaler. Det valgte systemopkald svarer til afstemningsfaciliteten , der blev introduceret i UNIX System V og senere operativsystemer. Men med c10k -problemet er både select og poll afløst af f.eks. Kqueue , epoll , /dev/poll og I/O -færdiggørelsesporte .
En almindelig brug af select uden for den angivne brug af at vente på filhåndteringer er at implementere en bærbar søvn under et sekund . Dette kan opnås ved at passere NULL for alle tre fd_set -argumenter og varigheden af den ønskede søvn som timeout -argument.
I programmeringssproget C erklæres det valgte systemopkald i overskriftsfilen sys/select.h eller unistd.h og har følgende syntaks:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
| argument | beskrivelse |
|---|---|
| nfds | Dette er et helt tal et mere end maksimumet for enhver filbeskrivelse i et af sætene. Med andre ord, mens du tilføjer filbeskrivere til hvert af sætene, skal du beregne den maksimale heltalværdi for dem alle, derefter øge denne værdi med en og derefter videregive denne som nfds. |
| readfds | fd_set type, der holder filbeskrivelserne, der skal kontrolleres for at være klar til læsning, og ved output angiver, hvilke filbeskrivelser der er klar til at læse. Kan være NULL . |
| skrevne | fd_set type, der holder filbeskrivelserne, der skal kontrolleres for at være klar til at skrive, og ved output angiver, hvilke filbeskrivelser der er klar til at skrive. Kan være NULL . |
| fejlfds | fd_set type, der holder filbeskrivelserne, der skal kontrolleres for fejlbetingelser , der afventer, og ved output angiver, hvilke filbeskrivelser der har ventende fejlbetingelser . Kan være NULL . |
| tiden er gået | struktur af typen struct timeval, der angiver et maksimalt interval, der skal vente på, at valget er afsluttet. Hvis timeout -argumentet peger på et objekt af typen struct timeval, hvis medlemmer er 0, blokerer select () ikke. Hvis timeout-argumentet er NULL, skal du vælge () blokke, indtil en hændelse får en af maskerne til at returneres med en gyldig (ikke-nul) værdi. Linux opdaterer timeout'en på plads for at angive, hvor lang tid der er gået, selvom denne adfærd ikke deles af de fleste andre Unix -systemer. |
fd_set typeargumenter kan manipuleres med fire hjælpemakroer: FD_SET (), FD_CLR (), FD_ZERO () og FD_ISSET () .
Select returnerer det samlede antal bits, der er angivet i readfds, writeefds og errorfds , eller nul, hvis timeout udløb, og -1 på fejl.
De sæt filbeskrivelser, der bruges i select, er begrænsede i størrelse, afhængigt af operativsystemet. Det nyere system opkald meningsmåling giver en mere fleksibel løsning.
Eksempel
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
#define PORT "9421"
/* function prototypes */
void die(const char*);
int main(int argc, char **argv)
{
int sockfd, new, maxfd, on = 1, nready, i;
struct addrinfo *res0, *res, hints;
char buffer[BUFSIZ];
fd_set master, readfds;
int error;
ssize_t nbytes;
(void)memset(&hints, '\0', sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
if (0 != (error = getaddrinfo(NULL, PORT, &hints, &res0)))
errx(EXIT_FAILURE, "%s", gai_strerror(error));
for (res = res0; res; res = res->ai_next)
{
if (-1 == (sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)))
{
perror("socket()");
continue;
}
if (-1 == (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int))))
{
perror("setsockopt()");
continue;
}
if (-1 == (bind(sockfd, res->ai_addr, res->ai_addrlen)))
{
perror("bind()");
continue;
}
break;
}
if (-1 == sockfd)
exit(EXIT_FAILURE);
freeaddrinfo(res0);
if (-1 == (listen(sockfd, 32)))
die("listen()");
if (-1 == (fcntl(sockfd, F_SETFD, O_NONBLOCK)))
die("fcntl()");
FD_ZERO(&master);
FD_ZERO(&readfds);
FD_SET(sockfd, &master);
maxfd = sockfd;
while (1)
{
memcpy(&readfds, &master, sizeof(master));
(void)printf("running select()\n");
if (-1 == (nready = select(maxfd+1, &readfds, NULL, NULL, NULL)))
die("select()");
(void)printf("Number of ready descriptor: %d\n", nready);
for (i=0; i<=maxfd && nready>0; i++)
{
if (FD_ISSET(i, &readfds))
{
nready--;
if (i == sockfd)
{
(void)printf("Trying to accept() new connection(s)\n");
if (-1 == (new = accept(sockfd, NULL, NULL)))
{
if (EWOULDBLOCK != errno)
die("accept()");
break;
}
else
{
if (-1 == (fcntl(new, F_SETFD, O_NONBLOCK)))
die("fcntl()");
FD_SET(new, &master);
if (maxfd < new)
maxfd = new;
}
}
else
{
(void)printf("recv() data from one of descriptors(s)\n");
nbytes = recv(i, buffer, sizeof(buffer), 0);
if (nbytes <= 0)
{
if (EWOULDBLOCK != errno)
die("recv()");
break;
}
buffer[nbytes] = '\0';
printf("%s", buffer);
(void)printf("%zi bytes received.\n", nbytes);
close(i);
FD_CLR(i, &master);
}
}
}
}
return 0;
}
void die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
Se også
- Berkeley stikkontakter
- Afstemning
- epoll
- kqueue
- Input/output -færdiggørelsesport (IOCP)
Referencer
eksterne links
- - Systemgrænseflader Reference, UNIX -specifikationen , nummer 7 fra The Open Group
- man-sider til
select(2)i FreeBSD, NetBSD, OpenBSD og DragonFly BSD