什么是select,为什么要用select
我们前面介绍过如何使用多进程的方式实现服务器,使服务器能同时和多个客户端相连接,那我可不可以使用一个进程就解决这个问题,答案是肯定的。使用select的主旨就是不让应用程序自己去监视连接,取而代之的使用内核来监视。而且select具有跨平台性,是不是觉得立马高端了不少,但是select的缺点也很明显我们后面在谈。
select的各个参数
先来看看selet这个函数
nfds 集合文件描述符的最大值+1
readfds 读集合
writefds 写集合
exceptfds 异常集合
timeout 限时 若是NULL,永久阻塞,若是具体值,限时阻塞等待
select的原理
每个进程都会默认打开三个文件描述符(0,1,2)即标准输入,输出,错误。那我们需要连接就需要新建一个文件描述符来对应accept(位置为3),那这个时候,客户端1和客户端2向我发来请求我就会分配给他们新的文件描述符,也就是ff1(4)和ff2(5)。
有了这个基本的了解就进入正题,select实现的是内核监听,但是内核如何去实现监听的。
举个例子
服务器用select选择这个文件描述符,意味着我要监听他,于是把他送入内核,到了内核,内核得到了消息,会先把这个值给清除掉,然后等待改变,如果改变了,就会把文件描述符重新写进去,然后重新给用户发过去,但是一定要清楚这里的的3是重新写进去的。
如果这个时候我们我们想要接收客户端发送的消息,那么我们需要在select的时候,需要将ff1和ff2添加进去,如果内核监听到了他们的变化,就会一块给用户发送回去。
了解到这一点就很容易发现select的缺点,没错,他暴露了。因为内核每次会先进行清除。所以我如果想要对他进行循环接收时。我就得每次在select时重新输入我想监听的东西,(突然觉得好麻烦)。所以我们最好备份一下自己想监听的东西,以免重复操作。
来个图
思路
代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <arpa/inet.h>
int main()
{
//创建socket
int fd = socket(AF_INET, SOCK_STREAM, 0