首先,在不同的操作系统下,select模型完全兼容么?
fd_set在2种操作系统下的实现方式差别比较大:
linux下面定义,对宏翻译后大概是这样的:
typedef struct
{
// 支持1024个文件描述符,而用bit作为掩码使用,每个long是64位,所以除以64
long int fds_bits[1024 / (8 * 8))];
} fd_set;
所以使用掩码方式可以直接按比特位进行设置,和删除;
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
man手册中说明,nfds并不是我们设置了多少个socket,而是最大的fd + 1;
这是因为
1)socket本身就是int从小到大的使用,当设置了最大的,最大值可以保证小的都被覆盖;
2)按照掩码方式使用,设置了大值,之前的都是需要监测的;
windows不同:
#define FD_SETSIZE 64
#endif /* FD_SETSIZE */
typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;
这里使用了一个很土的数组,加上一个使用的个数;
设置时候是
1)监测是否设置了;
2)如果找不到,则追加;
删除的时候是:
1)找到当前位置;
2)逐个向前挪动;
效率比linux的方式低了很多啊,
所以在使用select时候nfds的设置其实就是实际添加了多少个socket;
总结:为啥微软不采用掩码方式实现?是微软太笨么?
不是,是因为windows下socket的值并不是从小到大的一个递增的小整数,值可能会非常的大,所以不能使用小数组实现掩码。
另外:
`int retval, numevents = 0;
timeval tv;
tv.tv_sec =0;
tv.tv_usec = 0; // windows 设置为0合适
memcpy(&_rfds, &rfds, sizeof(fd_set));
memcpy(&_wfds, &wfds, sizeof(fd_set));
memcpy(&_efds, &efds, sizeof(fd_set));
//int n = efds.fd_count;
//n =max(_rfds.fd_count, _wfds.fd_count);
//if (n==0)
// return Utils::getmSecNow();
//printf("select n %d \n", n);
retval = select(maxFd + 1, &_rfds, &_wfds, &_efds, &tv);`

本文对比了select模型在Linux与Windows系统下的实现差异。Linux通过位掩码操作管理文件描述符,而Windows则采用数组记录的方式。文章详细解析了两种操作系统下select函数的工作原理,并解释了微软未采用位掩码的原因。

561

被折叠的 条评论
为什么被折叠?



