<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://arolstar52-zhtest.hf.space/index.php?action=history&amp;feed=atom&amp;title=Select_%28Unix%29</id>
	<title>Select (Unix) - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://arolstar52-zhtest.hf.space/index.php?action=history&amp;feed=atom&amp;title=Select_%28Unix%29"/>
	<link rel="alternate" type="text/html" href="https://arolstar52-zhtest.hf.space/index.php?title=Select_(Unix)&amp;action=history"/>
	<updated>2026-07-04T06:45:30Z</updated>
	<subtitle>在这个wiki上该页的修订历史</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://arolstar52-zhtest.hf.space/index.php?title=Select_(Unix)&amp;diff=663043&amp;oldid=prev</id>
		<title>imported&gt;Cwek：​/* 外部链接 */</title>
		<link rel="alternate" type="text/html" href="https://arolstar52-zhtest.hf.space/index.php?title=Select_(Unix)&amp;diff=663043&amp;oldid=prev"/>
		<updated>2026-02-22T03:45:21Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;外部链接&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{cleanup-jargon|time=2012-11-29T12:58:32+00:00}}&lt;br /&gt;
{{unreferenced|time=2010-05-05T08:01:28+00:00}}&lt;br /&gt;
{{lowercase}}&lt;br /&gt;
{{noteTA&lt;br /&gt;
|G1=IT&lt;br /&gt;
}}&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;select&amp;#039;&amp;#039;&amp;#039;是用于I/O多路转接的一个[[系统调用]]函数。&lt;br /&gt;
&lt;br /&gt;
在[[C语言]]中，该系统调用在 sys/select.h 或 [[unistd.h]] 中声明，语法如下：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, struct timeval* timeout);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!参数    !! 描述&lt;br /&gt;
|-&lt;br /&gt;
|&amp;#039;&amp;#039;nfds&amp;#039;&amp;#039;    || sets的文件描述符的最大值 &lt;br /&gt;
|-&lt;br /&gt;
|&amp;#039;&amp;#039;readfds&amp;#039;&amp;#039; || &amp;lt;tt&amp;gt;fd_set&amp;lt;/tt&amp;gt; 类型，包含了需要检查是否可读的描述符，输出时表示哪些描述符可读。可为 &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;。&lt;br /&gt;
|-&lt;br /&gt;
|&amp;#039;&amp;#039;writefds&amp;#039;&amp;#039;|| &amp;lt;tt&amp;gt;fd_set&amp;lt;/tt&amp;gt; 类型，包含了需要检查是否可写的描述符，输出时表示哪些描述符可写。可为 &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;。&lt;br /&gt;
|-&lt;br /&gt;
|&amp;#039;&amp;#039;errorfds&amp;#039;&amp;#039;|| &amp;lt;tt&amp;gt;fd_set&amp;lt;/tt&amp;gt; 类型，包含了需要检查是否出错的描述符，输出时表示哪些描述符出错。可为 &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;。&lt;br /&gt;
|-&lt;br /&gt;
|&amp;#039;&amp;#039;timeout&amp;#039;&amp;#039; || &amp;lt;tt&amp;gt;struct timeval&amp;lt;/tt&amp;gt; 类型的结构体，表示等待检查完成的最长时间。&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
为了维护fd_set类型的参数，会使用下面四个[[宏]]：FD_SET(), FD_CLR(), FD_ZERO() 和 FD_ISSET()。&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;返回值&amp;#039;&amp;#039;&amp;#039;：这个[[函数]]将返回描述符集的个数， 如果[[超时]]返回为0，错误则返回-1。&lt;br /&gt;
&lt;br /&gt;
[[Man (unix)|man]]参看：&lt;br /&gt;
*select(2) &lt;br /&gt;
*poll(2)&lt;br /&gt;
&lt;br /&gt;
==select与epoll的区别==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  &lt;br /&gt;
!  epoll&lt;br /&gt;
!  select&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| 概述 &lt;br /&gt;
| [[epoll]]是个[[模块]]，由三个[[系统调用]]组成，内核中由用[[文件系统]]实现&lt;br /&gt;
| [[select]]是个[[系统调用]]&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| 结构体定义 &lt;br /&gt;
| &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;typedef union epoll_data {&lt;br /&gt;
  void *ptr;&lt;br /&gt;
  int fd;&lt;br /&gt;
  __uint32_t u32;&lt;br /&gt;
  __uint64_t u64;&lt;br /&gt;
} epoll_data_t;&lt;br /&gt;
&lt;br /&gt;
struct epoll_event { &lt;br /&gt;
  __uint32_t events; // epoll 监听的事件类型&lt;br /&gt;
  epoll_data_t data; /* User data variable */&lt;br /&gt;
};&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|  &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;struct timeval{&lt;br /&gt;
  long tv_sec;//second&lt;br /&gt;
  long tv_usec;//minisecond&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
typedef struct fd_set {&lt;br /&gt;
  u_int fd_count;&lt;br /&gt;
  int fd_array[FD_SETSIZE];&lt;br /&gt;
} //fd_array可SIZE*8个socket&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|  可用的事件&lt;br /&gt;
|&lt;br /&gt;
EPOLLIN ：表示对应的文件描述符可以读；&amp;lt;br&amp;gt;&lt;br /&gt;
EPOLLOUT：表示对应的文件描述符可以写；&amp;lt;br&amp;gt;&lt;br /&gt;
EPOLLPRI：  表示对应的文件描述符有紧急的数据可读；&amp;lt;br&amp;gt;&lt;br /&gt;
EPOLLERR： 表示对应的文件描述符发生错误；&amp;lt;br&amp;gt;&lt;br /&gt;
EPOLLHUP：表示对应的文件描述符被挂断；&amp;lt;br&amp;gt;&lt;br /&gt;
EPOLLET：    ET的epoll工作模式；&lt;br /&gt;
&lt;br /&gt;
| fd_set有三种类型： &lt;br /&gt;
readfds,&lt;br /&gt;
writefds,&lt;br /&gt;
exceptionfds&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|  操作函数&lt;br /&gt;
|  三个系统调用：epoll_create   epoll_ctl epoll_wait&lt;br /&gt;
|  一个系统调用：select &amp;lt;br&amp;gt; 四个宏: FD_ZERO FD_SET FD_CLR FD_ISSET  &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|  运行模式&lt;br /&gt;
|  [[中断#边沿触发|边沿触发]] (ET)、[[中断#状态触发|状态触发]] (LT)&lt;br /&gt;
|  状态触发&lt;br /&gt;
|-&lt;br /&gt;
|  运行过程&lt;br /&gt;
|  &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;int fd = epoll_create(1); // 创建一个 epoll 实例，参数可以是任意正整数&lt;br /&gt;
struct epoll_event events[xxxB];// epoll 实例将发生的事件写入该数组&lt;br /&gt;
while(1){&lt;br /&gt;
	int nfds = epoll_wait(  );   // 等待事件发生&lt;br /&gt;
	for(int i=0; i&amp;lt;nfds; i++){&lt;br /&gt;
    …&lt;br /&gt;
	}//end for&lt;br /&gt;
}//end while&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
| &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;struct timeval tv;&lt;br /&gt;
fd_set rfds;&lt;br /&gt;
tv={5,0}; // 设置超时&lt;br /&gt;
while(1){&lt;br /&gt;
	FD_ZERO(&amp;amp;rfds);&lt;br /&gt;
	if (!select()) continue;&lt;br /&gt;
	for(int i=0;i&amp;lt;maxfds; i++){&lt;br /&gt;
		...&lt;br /&gt;
	} // 结束 for 循环&lt;br /&gt;
} // 结束 while 循环&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|  优点&lt;br /&gt;
|  1）epoll_wait返回的都是有效数据，可直接从struct epoll_event[]中获取事件，效率高。&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|  缺点&lt;br /&gt;
|  &lt;br /&gt;
| 每次select有数据要遍历全部socket &lt;br /&gt;
|-&lt;br /&gt;
|  注意事项&lt;br /&gt;
|  每次取事件后，要重新注册此socket的事件epoll。(epoll_ctl)&lt;br /&gt;
| 每次select之前要重置rfds的值。(FD_ZERO)&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;说明&amp;#039;&amp;#039;&amp;#039;：以上无论epoll_create, fd_set都受限于系统中单个进程能够打开的[[文件句柄]]数。&lt;br /&gt;
&lt;br /&gt;
== 示例 ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/socket.h&amp;gt;&lt;br /&gt;
#include &amp;lt;netinet/in.h&amp;gt;&lt;br /&gt;
#include &amp;lt;netdb.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;sys/select.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define PORT &amp;quot;9421&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/* function prototypes */&lt;br /&gt;
void die(const char*);&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	int sockfd, new, maxfd, on = 1, nready, i;&lt;br /&gt;
&lt;br /&gt;
	struct addrinfo *res0, *res, hints;&lt;br /&gt;
&lt;br /&gt;
	char buffer[BUFSIZ];&lt;br /&gt;
&lt;br /&gt;
	fd_set master, readfds;&lt;br /&gt;
&lt;br /&gt;
	ssize_t nbytes;&lt;br /&gt;
&lt;br /&gt;
	(void)memset(&amp;amp;hints, &amp;#039;\0&amp;#039;, sizeof(struct addrinfo));&lt;br /&gt;
&lt;br /&gt;
	hints.ai_family = AF_INET;&lt;br /&gt;
	hints.ai_socktype = SOCK_STREAM;&lt;br /&gt;
	hints.ai_protocol = IPPROTO_TCP;&lt;br /&gt;
	hints.ai_flags = AI_PASSIVE;&lt;br /&gt;
&lt;br /&gt;
	if(-1 == (getaddrinfo(NULL, PORT, &amp;amp;hints, &amp;amp;res0)))&lt;br /&gt;
		die(&amp;quot;getaddrinfo()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	for(res = res0; res; res = res-&amp;gt;ai_next)&lt;br /&gt;
	{&lt;br /&gt;
		if(-1 == (sockfd = socket(res-&amp;gt;ai_family, res-&amp;gt;ai_socktype, res-&amp;gt;ai_protocol)))&lt;br /&gt;
		{&lt;br /&gt;
			perror(&amp;quot;socket()&amp;quot;);&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		if(-1 == (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&amp;amp;on, sizeof(int))))&lt;br /&gt;
		{&lt;br /&gt;
			perror(&amp;quot;setsockopt()&amp;quot;);&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		if(-1 == (bind(sockfd, res-&amp;gt;ai_addr, res-&amp;gt;ai_addrlen)))&lt;br /&gt;
		{&lt;br /&gt;
			perror(&amp;quot;bind&amp;quot;);&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		break;&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if(-1 == sockfd)&lt;br /&gt;
		exit(EXIT_FAILURE);&lt;br /&gt;
&lt;br /&gt;
	freeaddrinfo(res0);&lt;br /&gt;
&lt;br /&gt;
	if(-1 == (listen(sockfd, 32)))&lt;br /&gt;
		die(&amp;quot;listen()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	if(-1 == (fcntl(sockfd, F_SETFD, O_NONBLOCK)))&lt;br /&gt;
		die(&amp;quot;fcntl()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	FD_ZERO(&amp;amp;master);&lt;br /&gt;
	FD_ZERO(&amp;amp;readfds);&lt;br /&gt;
	&lt;br /&gt;
	FD_SET(sockfd, &amp;amp;master);&lt;br /&gt;
&lt;br /&gt;
	maxfd = sockfd;&lt;br /&gt;
&lt;br /&gt;
	while(1)&lt;br /&gt;
	{&lt;br /&gt;
		memcpy(&amp;amp;readfds, &amp;amp;master, sizeof(master));&lt;br /&gt;
&lt;br /&gt;
		(void)printf(&amp;quot;running select()\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		if(-1 == (nready = select(maxfd+1, &amp;amp;readfds, NULL, NULL, NULL)))&lt;br /&gt;
			die(&amp;quot;select()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		(void)printf(&amp;quot;Number of ready descriptor: %d\n&amp;quot;, nready);&lt;br /&gt;
&lt;br /&gt;
		for(i=0; i&amp;lt;=maxfd &amp;amp;&amp;amp; nready&amp;gt;0; i++)&lt;br /&gt;
		{&lt;br /&gt;
			if(FD_ISSET(i, &amp;amp;readfds))&lt;br /&gt;
			{&lt;br /&gt;
				nready--;&lt;br /&gt;
&lt;br /&gt;
				if(i == sockfd)&lt;br /&gt;
				{&lt;br /&gt;
					(void)printf(&amp;quot;Trying to accept() new connection(s)\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
					if(-1 == (new = accept(sockfd, NULL, NULL)))&lt;br /&gt;
					{&lt;br /&gt;
						if(EWOULDBLOCK != errno)&lt;br /&gt;
							die(&amp;quot;accept()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
						break;&lt;br /&gt;
					}&lt;br /&gt;
					&lt;br /&gt;
					else&lt;br /&gt;
					{&lt;br /&gt;
&lt;br /&gt;
						if(-1 == (fcntl(new, F_SETFD, O_NONBLOCK)))&lt;br /&gt;
							die(&amp;quot;fcntl()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
						FD_SET(new, &amp;amp;master);&lt;br /&gt;
&lt;br /&gt;
						if(maxfd &amp;lt; new)&lt;br /&gt;
							maxfd = new;&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				else&lt;br /&gt;
				{&lt;br /&gt;
					(void)printf(&amp;quot;recv() data from one of descriptors(s)\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
					nbytes = recv(i, buffer, sizeof(buffer), 0);&lt;br /&gt;
					if(nbytes &amp;lt;= 0)&lt;br /&gt;
					{&lt;br /&gt;
						if(EWOULDBLOCK != errno)&lt;br /&gt;
							die(&amp;quot;recv()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
						break;&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
					buffer[nbytes] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
					printf(&amp;quot;%s&amp;quot;, buffer);&lt;br /&gt;
					&lt;br /&gt;
					(void)printf(&amp;quot;%zi bytes received.\n&amp;quot;, nbytes);&lt;br /&gt;
&lt;br /&gt;
					close(i);&lt;br /&gt;
					FD_CLR(i, &amp;amp;master);&lt;br /&gt;
&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void die(const char *msg)&lt;br /&gt;
{&lt;br /&gt;
	perror(msg);&lt;br /&gt;
	exit(EXIT_FAILURE);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 参见 ==&lt;br /&gt;
*[[Berkeley套接字]]&lt;br /&gt;
*[[轮询]]&lt;br /&gt;
*[[epoll]]&lt;br /&gt;
*[[kqueue]]&lt;br /&gt;
*[[IOCP]]&lt;br /&gt;
&lt;br /&gt;
== 外部链接 ==&lt;br /&gt;
* {{man|2|select|Linux}}&lt;br /&gt;
* {{man|2|select_tut|die.net}}&lt;br /&gt;
&lt;br /&gt;
{{Linux内核}}&lt;br /&gt;
[[Category:C POSIX库]]&lt;br /&gt;
[[Category:事件 (计算机)]]&lt;br /&gt;
[[Category:系统调用]]&lt;/div&gt;</summary>
		<author><name>imported&gt;Cwek</name></author>
	</entry>
</feed>