一 五种网络I/O模型
在Linux下进行网络编程时,服务器端编程经常需要构造高性能的IO模型,常见的IO模型有五种:
(1)同步阻塞IO
(2)同步非阻塞IO(Non-blocking IO)
(3)IO多路复用(IO Multiplexing)
:IO多路复用模型是建立在内核提供的多路分离函数select基础之上的,使用select函数 可以避免同步非阻塞IO模型中轮询等待的问题,此外poll、epoll都是这种模型。
(4) 信号驱动IO(signal driven IO)
(5)异步IO(Asynchronous IO)
各服务器源代码:https://gitee.com/constructorvirgil/lingyun_apue/tree/master/yangjianing
二 多路复用–select
select()函数允许进程指示内核等待多个事件(文件描述符)中的任何一个发生,并只在有一个或多个事件发生或经历一段指定时 间后才唤醒它,然后接下来判断究竟是哪个文件描述符发生了事件并进行相应的处理。
#include <sys/select.h>
#include <sys/time.h>
struct timeval
{
long tv_sec; //seconds
long tv_usec; //microseconds
};
FD_ZERO(fd_set* fds) //清空集合
FD_SET(int fd, fd_set* fds) //将给定的描述符加入集合
FD_ISSET(int fd, fd_set* fds) //判断指定描述符是否在集合中
FD_CLR(int fd, fd_set* fds) //将给定的描述符从文件中删除
看一下函数原型
int select(int max_fd, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout);
1 第一个参数max_fd指待测试的fd的总个数,它的值是待测试的最大文件描述符加1
2 中间三个参数readset、writeset和exceptset指定要让内核测试读、写和异常条件的fd集合,如果不需要测试的可以设置为 NULL;
3 最后一个参数是设置select的超时时间,如果设置为NULL则永不超时
下面是使用select()多路复用实现的服务器端示例代码:(只贴出主要部分)
for(i=0; i<ARRAY_SIZE(fds_array); i++)
{
fds_array[i] = -1; //说明该位置为空
}
fds_array[0]=listenfd;
while (1)
{
FD_ZERO(&rdset); //清零
for(i=0; i< ARRAY_SIZE(fds_array);i++) //遍历该数组
{
if (fds_array[i]<0)
{
continue;
}
maxfd = fds_array[i]>maxfd ? fds_array[i] : maxfd;
FD_SET(fds_array[i], &rdset);
}
}
rv = select(maxfd+1, &rdset, NULL, NULL, NULL);
if (rv < 0)
{
printf("select failure: %s\n",strerror(errno));
break ;
}
else if (rv == 0)
{
printf("select get timeout\n");
continue;
}
if (FD_ISSET(listenfd, &rdset)) //是否是新客户端链接
{
if(connfd = accept(listenfd, (struct sockaddr *)NULL,NULL) < 0)
{
printf("accept new client failure : %s\n",strerror(errno));
return -4;
}
found = 0;
for(i=0; i<ARRAY_SIZE(fds_array);i++)
{