windows select模型 和linux的区别
发布网友
发布时间:2022-05-01 05:39
我来回答
共2个回答
热心网友
时间:2022-06-25 03:13
windows
select模型
在widows下提供了众多非阻塞的I/O模型,如select、WSAAsyncSelect、WSAEventSelect、overlapped、completion
port,其中IO
completion
port(IOCP)提供了较好的伸缩性,在windows应用比较广泛
说明:而select模型主要是解决在单一线程模式下只能处理一个套接字的问题,这样可以避免线程膨胀问题,但是。。。下面看完原型再讲起不足之处
select模型:winsock库主要有两个版本,这里主要以winsock2版本为说明,select模型
int
select(int
nfds,fd_set*
readfds,fd_set*
writefds,fd_set*
exceptfds,const
struct
timeval*
timeout);
其实主要是两者采用的标准一致,所以接口基本跟linux一致,不过nfds在windows其实是没有意义的,主要是为了兼容其他版本
处理过程:假设以read为例,在这里windows主要是先将套接字s添加到readfds集合中,然后等待select函数返回,在select函数里面会移除没有未决的
I/O操作的套接字句柄,即已经处理过的IO套接字句柄,然后看s是否认仍然还是readfs集合中,在就说明s可读了,但是这里面可读,不一定有数据
有几种情况都会引发:数据可读、连接关闭/重启/中断、监听套接字被调用,此时还有连接未决,accept函数接受新的套接字成功
不足:其实添加到fd_set套接字数量是有*的,winsock2.h定义的64,自定义也不超过1024,因为值太大,会对服务器的性能有影响,更高的就是可伸缩的IOCP
linux
select模型
其实原理跟windows是差不多的,只是处理过程在底层上有点区别
模型:int
select(int
maxfd,fd_set*readfds,fd_set*
writefds,fd_set*exceptfds,const
struct
timeval*timeout)
这里主要是maxfd,文件描述符的范围,比待检测的最大文件描述符大1
处理过程:也是先将监控的文件添加到文件描述符集合中,调用select监控,判断文件是否发生变化,但是在底层调用的确是poll方法;首先使用poll_wait将等待队列添加到poll_table中,返回描述符的掩码
poll原型:unsigned
int
(*poll)(struct
file*filp,poll_wait*
wait)
看如下一个简单的处理过程
unsigned
int
mem_poll(struct
file
*filp,
poll_table
*wait)
{
struct
mem_dev
*dev
=
filp->private_data;
unsigned
int
mask
=
0;
/*将等待队列添加到poll_table
*/
poll_wait(filp,
&dev->inq,
wait);
if
(have_data)
mask
|=
POLLIN
|
POLLRDNORM;
/*
readable
*/
return
mask;
}
在这里只是添加队列,返回可读可写的掩码,真正阻塞的不是这里,是在do_select(...)函数中,在linux内核fs/select.c里面
int
do_select(int
n,
fd_set_bits
*fds,
struct
timespec
*end_time)这个函数
if
(file)
{
f_op
=
file->f_op;
mask
=
DEFAULT_POLLMASK;
if
(f_op
&&
f_op->poll)
{
wait_key_set(wait,
in,
out,
bit);
mask
=
(*f_op->poll)(file,
wait);
}
这里面是先判断文件存在,然后读取你自己定义的操作设备I/O的f_op函数,这里有一个默认的mask,接着才判断然后返回描述符mask
=
(*f_op->poll)(file,
wait);用于区分当前哪个集合被触发了;接着判断f_op&f_op->poll在这里我们默认定义了poll函数,所以这里会进入此判断语句,mask
=
(*f_op->poll)(file,
wait);这个就是调用默认的poll函数进行处理,关键的是如何区分不同的读、写、异常过程?
(mask
&
POLLIN_SET)
&&
(in
&
bit),这里面就是对当前的可读、写、异常的&&过程,就是为了判断和区分当前的套接字只是某一个具体的fd_set集合下;当然某一个套接字也可能同时在可读可写里面,这时候两个会进行判断。
if
(retval
||
timed_out
||
signal_pending(current))
break;
上面的retval如果为0,且其他也不满足就会导致空循环状态,就处于阻塞状态了
热心网友
时间:2022-06-25 03:14
本质上没有什么区别,都是轮询而已