(Translated by https://www.hiragana.jp/)
select (Unix) - 维基百科,自由的百科全书 とべ转到内容ないよう

select (Unix)

本页使用了标题或全文手工转换
维基百科ひゃっか自由じゆうてき百科ひゃっかぜん

selectよう于I/Oみち转接てきいちけい统调よう函数かんすう

ざいCほどじょちゅう,该系统调ようざい sys/select.h ある unistd.h ちゅう声明せいめい,语法如下:

int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, struct timeval* timeout);
さんすう 描述
nfds setsてきぶんけん描述てき最大さいだい
readfds fd_set 类型,包含ほうがんりょう需要じゅよう检查いや读的描述,输出时表示ひょうじ哪些描述读。NULL
writefds fd_set 类型,包含ほうがんりょう需要じゅよう检查いやうつしてき描述,输出时表示ひょうじ哪些描述うつしNULL
errorfds fd_set 类型,包含ほうがんりょう需要じゅよう检查错的描述,输出时表示ひょうじ哪些描述错。NULL
timeout struct timeval 类型てき结构たい表示ひょうじとうまち检查完成かんせいてきさい长时间。

为了维护fd_set类型てきさんすうかい使用しよう下面かめんよんひろし:FD_SET(), FD_CLR(), FD_ZERO() かず FD_ISSET()。

かえしかい

      这个函数かんすうはたかえしかい描述しゅうてき个数, 如果ちょうかえしかい为0,错误则返かい-1。

参看さんかん

  • select(2)
  • poll(2)

selectあずかepollてき

[编辑]
epoll select
がいじゅつ epollかたぎよしさんけい统调よう组成,ないかくちゅうよしようぶんけんけい实现 selectけい统调よう
结构たいてい
typedef union epoll_data {
  void *ptr;
  int fd;
  __uint32_t u32;
  __uint64_t u64;
} epoll_data_t;

struct epoll_event { 
  __uint32_t events; // epoll 监听てき事件じけん类型
  epoll_data_t data; /* User data variable */
};
struct timeval{
  long tv_sec;//second
  long tv_usec;//minisecond
}

typedef struct fd_set {
  u_int fd_count;
  int fd_array[FD_SETSIZE];
} //fd_arraySIZE*8个socket
可用かようてき事件じけん

EPOLLIN :表示ひょうじ对应てきぶんけん描述以读;
EPOLLOUT:表示ひょうじ对应てきぶんけん描述以写;
EPOLLPRI: 表示ひょうじ对应てきぶんけん描述ゆう紧急てきすうすえ读;
EPOLLERR: 表示ひょうじ对应てきぶんけん描述发生错误;
EPOLLHUP:表示ひょうじ对应てきぶんけん描述挂断;
EPOLLET: ETてきepoll工作こうさくしき

fd_setゆうさん种类がた

readfds, writefds, exceptionfds


操作そうさ函数かんすう さん个系统调よう:epoll_create epoll_ctl epoll_wait いち个系统调よう:select
よん个宏: FD_ZERO FD_SET FD_CLR FD_ISSET
运行しき 边沿触发 (ET)、じょう态触发 (LT)  じょう态触发
运行过程  
int fd = epoll_create(1); // 创建いち个 epoll 实例,まいりすう以是任意にんいせい整数せいすう
struct epoll_event events[xxxB];// epoll 实例はた发生てき事件じけんうつしにゅう该数组
while(1){
	int nfds = epoll_wait(  );   // とうまち事件じけん发生
	for(int i=0; i<nfds; i++){
    
	}//end for
}//end while
struct timeval tv;
fd_set rfds;
tv={5,0}; // 设置ちょう
while(1){
	FD_ZERO(&rfds);
	if (!select()) continue;
	for(int i=0;i<maxfds; i++){
		...
	} // 结束 for 循环
} // 结束 while 循环
优点 1)epoll_waitかえしかいてき有效ゆうこうすうすえ直接ちょくせつ从struct epoll_event[]ちゅう获取事件じけん效率こうりつだか
缺点けってん 每次まいじselect有数ゆうすうすえようあまね历全socket
注意ちゅういごと 每次まいじ事件じけんきさきようじゅうしんちゅうさつ此socketてき事件じけんepoll。(epoll_ctl) 每次まいじselectぜんようじゅうおけrfdsてき值。(FD_ZERO)

说明以上いじょう无论epoll_create, fd_set受限于系统中单个进程のう够打开的ぶんけん句柄くがらかず

しめせれい

[编辑]
#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 <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;

	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(-1 == (getaddrinfo(NULL, PORT, &hints, &res0)))
		die("getaddrinfo()");

	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);
}

まいり

[编辑]

外部がいぶ链接

[编辑]