select模型

高级io:

五种io模型:阻塞io  非阻塞io  信号驱动io  异步io  多路转接io

多路转接io模型:select  poll   epoll

五种io模型 :

IO操作分为两个过程:等待+数据拷贝

阻塞:为了完成功能发起调用,若当前不具备完成条件,则一直等待完成后发起调用返回

非阻塞:为了完成功能发起调用,若当前不具备完成条件,直接报错返回,通常需要循环处理

阻塞与非阻塞区别:发起调用后是否会立即返回

同步:为了完成功能发起调用,若当前不具备完成条件,则等待完成功能后返回

异步:为了完成功能发起调用,但是功能有别人来完成

同步与异步的区别:功能是否有自己完成

异步:

       异步阻塞操作:等待别人完成操作

       异步非阻塞操作:不等待别人完成操作

同步与异步的优缺点:同步流程控制简单但是效率低下;异步流程控制较难,但是效率相对较高

多路转接io/多路复用io

        是对一种io事件的监控;同时对大量的描述符进行事件监控;监控描述符是否具备io条件;

        多路转接模型:都是对大量的描述符进行时间监控操作

        就绪:

                对于可读事件来说,缓冲区有数据就是读就绪

                对于可写时间来说,缓冲区中有空闲空间就是写就绪

select模型:

 

优缺点分析:

     1.select所能监控的描述符有上限------_FD_SETSIZE

     2.select需要用户将描述符集合拷贝到内核当中

     3.select在内核当中使用遍历轮询的方式检测描述符是否就绪;性能随着描述符增多而降低

     4.select不会告诉用户具体哪一个描述符就绪,需要用户遍历所有描述符进行查找;性能随着描述符的增多而降低,并且增加了代码的复杂度 

     5.select监控,返回值会修改监控集合(移除未就绪的描述符);需要用户每次监控前重新添加描述符到集合当中

     6.遵循posix标准。可以跨平台

     7.监控时常可以精细到微秒

  1. 针对描述符不同的事件定义不用的事件集合fd_set;(可读/可写/异常)
  2. 将指定的描述符描述符按照不同的所关心的事件添加到不同的集合当中
  3. 在内核当中对这些集合当中的描述符进行遍历轮询的方式进行监控(这个监控是阻塞的)
  4. 集合当中的描述符就绪时,将集合当中的未就绪描述符从集合当中移除,返回用户获取到的集合中的都是就绪的描述符
  5. 用户遍历所有描述符,看哪一个在集合当中,哪一个就是就绪的,进而对其进行操作

int select (int maxfds,fd_set* readfds,fd_set* writefds,fd_set* execptfds,struct timeval* timeout);

fd_set : 描述符集合---是一个位图-大小取决于_FD_SETSIZE=1024;

maxfds : 监控的描述符中,最大的那个描述符+1

readfds : 都事件集合

writefds:写事件集合

execptfds:异常事件集合

timeout:select等待超时时间

代码实现


    1  #include <vector>                                                                                 
    2 #include <iostream>
    3 #include <sys/select.h>
    4 #include "tcpsocket.hpp"
    5 
    6 class Select
    7 {
    8     public:
    9         Select():_max_fd(-1){
   10             //void FD_ZERO(fd_set *set);
   11             //清空集合
   12             FD_ZERO(&_rfds);
   13         }
   14         bool Add(TcpSocket &sock) {
   15             //void FD_SET(int fd, fd_set *set);
   16             //将指定描述符添加到集合中
   17             int fd = sock.GetSockFd();
   18             FD_SET(fd, &_rfds);
   19             _max_fd = (fd > _max_fd) ? fd : _max_fd;
   20             return true;
   21         }
   22         bool Del(TcpSocket &sock) {
   23             //void FD_CLR(int fd, fd_set *set);
   24             //从集合中移除指定的描述符
   25             int fd = sock.GetSockFd();
   26             FD_CLR(fd, &_rfds);
   28             for (int i = _max_fd; i >= 0; i--) {
   29                 //int  FD_ISSET(int fd, fd_set *set);
   30                 //判断描述符是否在集合中
   31                 //从max向前遍历,还在集合中的第一个就是最大的
   32                 if (!FD_ISSET(i, &_rfds)) {
   33                     continue;
   34                 }
   35                 _max_fd = i;
   36                 break;
   37             }
   38             return true;
   39         }
   40         bool Wait(std::vector<TcpSocket> &list, int timeout = 3000) {
   41             //int select(int nfds, fd_set *readfds, fd_set *writefds,
   42             //  fd_set *exceptfds, struct timeval *timeout);
   43             //返回值:>0 就绪的描述符个数   ==0 等待超时    <0 监控出错
   44             fd_set rfds = _rfds;
   45             struct timeval tv;
   46             tv.tv_sec = 0;
   47             tv.tv_usec = timeout * 1000;
   48             int ret = select(_max_fd + 1, &rfds, NULL, NULL, &tv);
   49             if (ret < 0) {                                                                        
   50                 perror("select error");
   51                 return false;
   52             }else if (ret == 0) {
   53                 std::cout << "timeout!!\n";
   54                 return false;
  28             for (int i = _max_fd; i >= 0; i--) {
   29                 //int  FD_ISSET(int fd, fd_set *set);
   30                 //判断描述符是否在集合中
   31                 //从max向前遍历,还在集合中的第一个就是最大的
   32                 if (!FD_ISSET(i, &_rfds)) {
   33                     continue;
   34                 }
   35                 _max_fd = i;
   36                 break;
   37             }
   38             return true;
   39         }
   40         bool Wait(std::vector<TcpSocket> &list, int timeout = 3000) {
   41             //int select(int nfds, fd_set *readfds, fd_set *writefds,
   42             //  fd_set *exceptfds, struct timeval *timeout);
   43             //返回值:>0 就绪的描述符个数   ==0 等待超时    <0 监控出错
   44             fd_set rfds = _rfds;
   45             struct timeval tv;
   46             tv.tv_sec = 0;
   47             tv.tv_usec = timeout * 1000;
   48             int ret = select(_max_fd + 1, &rfds, NULL, NULL, &tv);
   49             if (ret < 0) {                                                                        
   50                 perror("select error");
   51                 return false;
   52             }else if (ret == 0) {
   53                 std::cout << "timeout!!\n";
   54                 return false;
   55             }
   56             //因为select返回后集合中保存的都是就绪的描述符(没有就绪的已经被移除)
   57             for (int i = 0; i <= _max_fd; i++) {
   58                 if (FD_ISSET(i, &rfds)) {
   59                     TcpSocket sock;
   60                     sock.SetSockFd(i);
   61                     list.push_back(sock);
   62                 }
   63             }
   64             return true;
   65         }
   66     private:
   67         fd_set _rfds;
   68         int _max_fd;
   69 };
   70 
   71 int main()
   72 {
   73     TcpSocket sock;
   74     CHECK_RET(sock.Socket());
   75     CHECK_RET(sock.Bind("0.0.0.0", 9000));
   76     CHECK_RET(sock.Listen());                                                                     
   77 
   78     Select s;
   79     s.Add(sock);
   80     while(1) {
   81         std::vector<TcpSocket> list;
   82         bool ret = s.Wait(list);
   83         if (ret == false) {
   84             continue;
   85         }
W> 86         for (int i = 0; i < list.size(); i++) {
   87             //遍历就绪列表,若就绪的描述符和监听描述符相等
   88             //应该获取新连接的客户端socket
   89             if (list[i].GetSockFd() == sock.GetSockFd()) {
   90                 TcpSocket clisock;
   91                 ret = sock.Accept(clisock);
   92                 if (ret == false) {
   93                     continue;
   94                 }
   95                 s.Add(clisock);
   96             }else {
   97                 std::string buf;
   98                 ret = list[i].Recv(buf);
   99                 if (ret == false) {
  100                     s.Del(list[i]);
  101                     list[i].Close();
  102                 }
  103                 std::cout << "client say: "<< buf << std::endl;                                   
  104             }
  105         }
  106     }
  107     sock.Close();
  108     return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值