日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

IO多路转接模型----(select的模型,select的优缺点,poll的模型,poll的优缺点)

發布時間:2023/11/30 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IO多路转接模型----(select的模型,select的优缺点,poll的模型,poll的优缺点) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

IO多路轉接模型:select/poll/epoll

對大量描述符進行事件監控(可讀/可寫/異常)

select模型

  • 用戶定義描述符的事件監控集合 fd_set(這是一個位圖,用于存儲要監控的描述符); 用戶將需要監控的描述符添加到集合中,這個描述符集合的大小取決于一個宏 _FD_SETSIZE = 1024
  • 將集合拷貝到內核中進行監控;在內核中對所有描述符進行輪詢遍歷判斷是否有關心的事件就緒
  • 若有描述符就緒,從監控集合中將未就緒的描述符移除;然后調用返回(返回給用戶就緒描述符饑集合)
  • 用戶遍歷所有描述符,判斷描述符是否在集合中,若在集合中,則這個描述符是就緒描述符
  • 用戶針對這個就緒的描述符事件進行相應的處理,用戶僅僅對大量描述符中就緒的描述符進行處理,sock程序就可以避免accept/recv處因為沒有數據到來而阻塞
  • #include <sys/select.h> /* According to earlier standards */ #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select(int nfds, fd_set *readfds,fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    • nfds: 監控的文件描述符集里最大文件描述符加1,因為此參數會告訴內核檢測前多少個文件描述符的狀態
    • readfds: 監控有讀數據到達文件描述符集合,傳入傳出參數
    • writefds: 監控寫數據到達文件描述符集合,傳入傳出參數
    • exceptfds: 監控異常發生達文件描述符集合,如帶外數據到達異常,傳入傳出參數
    • timeout: 定時阻塞監控時間,3種情況
    • NULL,永遠等下去
    • 設置timeval,等待固定時間
    • 設置timeval里時間均為0,檢查描述字后立即返回,輪詢
    struct timeval { long tv_sec; /* seconds */ //秒 long tv_usec; /* microseconds */ //微秒 };
    • void FD_CLR(int fd, fd_set *set); //把文件描述符集合里fd清0 將指定的描述符從集合中移除
    • int FD_ISSET(int fd, fd_set *set); //測試文件描述符集合里fd是否置1 判斷指定的描述符是否在集合中
    • void FD_SET(int fd, fd_set *set); //把文件描述符集合里fd位置1 將指定的描述符添加到集合中
    • void FD_ZERO(fd_set *set); //把文件描述符集合里所有位清0 清空描述符集合

    select優缺點

  • select 能監聽的文件描述符個數受限于 FD_SETSIZE,一般為 1024,單純改變進程打開的文件描述符個數并不 能改變 select 監聽文件個數
  • 每次都需要重新將監控集合拷貝到內核(select會修改集合)
  • 解決 1024 以下客戶端時使用 select 是很合適的,但如果鏈接客戶端過多,select 采用的是輪詢模型,會大大降低服務器響應效率
  • select返回給用戶就緒的描述符集合(將未就緒的描述符從集合中移除),但是并沒有告訴用戶具體哪一個描述符就緒,需要用戶遍歷描述符是否在集合中來判斷哪個描述符就緒,這個判斷是一個遍歷的過程,性能隨著描述符增多而下降,并且復雜度更高
  • select每次返回都會修改監控集合,因此每次都需要用戶重新向集合中添加所有描述符
  • select遵循posix標準,支持跨平臺;
  • 監控的超時等待時間可以精細到微秒
  • class Select { public:Add(TcpSocket &sock); //將用戶關心socket描述符添加到監控集合中Del(TcpSocket &sock); //從監控集合中移除不再關心的socket描述符Wait(std::vector<TcpSocket>&list,init timeout_sec,int timeout_sec); //從開始監控,并且向用戶返回就緒的socket private:fd_set _rfds;int_max_fd; };

    實現

    select服務端

    /** 這個文件封裝一個select類,向外界提供更加簡單點的select監控接口* 將用戶關心socket描述符添加到監控集合中* 從監控集合中移除不再關心的socket描述符* 從開始監控,并且向用戶返回就緒的socket*/#include<vector> #include<sys/select.h> #include"tcpsocket.hpp"class Select {public:Select(): _max_fd (-1){FD_ZERO(&_rfds);//清空集合} bool Add(TcpSocket &sock){int fd = sock.GetFd();//void FD_SET(int fd,fd_set *set)//向set描述符集合中添加fd描述符FD_SET(fd,&_rfds);_max_fd = _max_fd > fd ? _max_fd : fd; return true;} bool Del(TcpSocket &sock){int fd = sock.GetFd();//void FD_CLR(int fd, fd_set *set)//從set描述符集合中移除FD_CLR(fd,&_rfds);//從最大的往前遍歷for(int i = _max_fd ; i >= 0; i--){//int FD_ISSET(int fd, fd_set *set);//判斷fd描述符是否還在set集合中if(FD_ISSET(i,&_rfds)){_max_fd = i;break;}}} bool Wait(std::vector<TcpSocket>&list,int timeout_sec = 3){struct timeval tv; //超時時間tv.tv_sec = timeout_sec;tv.tv_usec = 0;fd_set set = _rfds;int ret =select(_max_fd + 1, &set, NULL ,NULL,&tv);if(ret < 0){perror("select error");return false;}else if(ret == 0){std::cout<< "select wait timeout\n";return false;}for(int i =0 ;i <= _max_fd; i++){if(FD_ISSET(i,&set)){TcpSocket sock;sock.SetFd(i);list.push_back(sock);}}return true;} private:fd_set _rfds;int _max_fd; };int main() {TcpSocket sock;CHECK_RET(sock.Socket());CHECK_RET(sock.Bind("192.168.145.132",9000));CHECK_RET(sock.Listen());Select s;s.Add(sock); while(1){std::vector<TcpSocket>list;if(s.Wait(list)==false){continue;}for(int i =0 ; i < list.size(); i++){//判讀socket是監聽socket還是通信socketif(list[i].GetFd() == sock.GetFd()){TcpSocket clisock;std::string cli_ip;uint16_t cli_port;if(sock.Accept(clisock,cli_ip,cli_port) == false){continue;}s.Add(clisock);}else{std::string buf;if(list[i].Recv(buf) == false){s.Del(list[i]);list[i].Close();continue;}std::cout<<"client say:"<<buf <"\n";}}}sock.Close();return 0; }

    客戶端

    #include <signal.h> #include "tcpsocket.hpp"void sigcb(int signo){printf("connection closed\n"); } int main(int argc, char *argv[]) {if (argc != 3) {std::cout<<"./tcp_cli 192.168.122.132 9000\n";return -1; } std::string ip = argv[1];uint16_t port = atoi(argv[2]);signal(SIGPIPE, sigcb);TcpSocket sock;CHECK_RET(sock.Socket());CHECK_RET(sock.Connect(ip, port));while(1) {std::string buf;std::cout <<"client say:";fflush(stdout);std::cin >>buf;sock.Send(buf);}sock.Close();return 0; }



    poll模型

    poll函數接口

    #include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);// pollfd結構 struct pollfd { int fd; /* 用戶監控的描述符 */ short events; /* 描述符關心的事件 POLLIN/POLLOUT */ short revents; /* 描述符實際就緒的事件 */ }
    參數說明
    • fds是一個poll函數監聽的結構列表. 每一個元素中, 包含了三部分內容: 文件描述符, 監聽的事件集合, 返回的事件集合. 描述事件結構數組
    • nfds表示fds數組的長度. 要監控事件個數
    • timeout表示poll函數的超時時間, 單位是毫秒(ms).
    events和revents的取值:
  • POLLIN 普通或帶外優先數據可讀,即POLLRDNORM | POLLRDBAND
  • POLLRDNORM 數據可讀
  • POLLRDBAND 優先級帶數據可讀
  • POLLPRI 高優先級可讀數據
  • POLLOUT 普通或帶外數據可寫
  • POLLWRNORM 數據可寫
  • POLLWRBAND 優先級帶數據可寫
  • POLLERR 發生錯誤
  • POLLHUP 發生掛起
  • POLLNVAL 描述字不是一個打開的文件
  • 實現原理

  • 用戶定義描述符事件數組,向數組中添加關心的描述符事件
  • 將pollfd事件數組,拷貝到內核中進行遍歷輪詢監控,判斷是否就緒了關心的事件
  • 將描述符實際就緒的事件信息,標記到revents中
  • 當poll返回。用戶遍歷pollfd事件數組,通過revents判斷描述符就緒了什么事件,進而進行相應操作
  • 使用poll監控標準輸入

    #include <poll.h> #include <unistd.h> #include <stdio.h>int main() { struct pollfd poll_fd; //一個結構就是一個事件poll_fd.fd = 0; poll_fd.events = POLLIN; //可讀事件for (;;) { //開始監控int ret = poll(&poll_fd, 1, 1000); //遍歷輪詢 if (ret < 0) { //出錯perror("poll"); continue; }if (ret == 0) { //超時printf("poll timeout\n"); continue; } //ret>0if (poll_fd.revents == POLLIN) { //看事件是否為我們所關心的事件 //對事件進行操作 char buf[1024] = {0}; read(0, buf, sizeof(buf) - 1); printf("stdin:%s", buf); } } }

    poll有缺點分析

    優點:
  • poll采用事件結構形式對描述符關心的事件進行監控,簡化了select三種集合操作的流程
  • poll沒有描述符上限的設置
  • 缺點
  • 不能跨平臺,只能用于Linux下
  • 在內核中進行輪詢遍歷判斷就緒,性能隨著描述符事件增多而下降
  • 也不會告訴用戶具體哪一個描述符就緒,需要用戶輪詢遍歷判斷事件中的revents;進而對描述符進行相應事件操作 revents & POLLIN/POLLOUT
  • 需要每次都向內核中拷貝監控信息
  • 總結

    以上是生活随笔為你收集整理的IO多路转接模型----(select的模型,select的优缺点,poll的模型,poll的优缺点)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。