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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

IO多路转接之poll

發布時間:2024/4/11 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IO多路转接之poll 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

IO多路轉接之poll

文章目錄

  • IO多路轉接之poll
    • 一、Poll

一、Poll

  • 1.函數原型:
int poll(struct pollfd *fds, nfds_t nfds, int timeout); 參數作用
struct pollfd *fdsfds是一個poll函數監聽的結構列表. 每一個元素中, 包含了三部分內容: 文件描述符, 監聽的事件集合, 返回的事件集合
nfds_t nfdsnfds表示fds數組的長度
timeouttimeout表示poll函數的超時時間, 單位是毫秒(ms)

返回值

  • 返回值小于0, 表示出錯;
  • 返回值等于0, 表示poll函數等待超時;
  • 返回值大于0, 表示poll由于監聽的文件描述符就緒而返回
  • 2.理解struct pollfd *fds
// pollfd結構 struct pollfd {int fd; /* file descriptor */short events; /* requested events */short revents; /* returned events */ };

其中enent和revent的取值(主要取值),不清楚可以找Man

取值描述
POLLIN數據可讀(普通數據和優先級數據)
POLLOUT數據可寫(普通數據和優先級數據)
POLLERR錯誤
  • 3.socket就緒條件

  • 讀就緒

  • sochet內核中,接收緩沖區中的字節數,大于等于低水位標記SO_RECVLOWAT,此時可以無阻塞的讀該文件描述符,并且返回值大于0

  • socket TCP通信中,對端關閉連接,此時對該socket讀,則返回0 監聽的socket上有新的連接請求時

  • socket上有未處理的錯誤時

  • 寫就緒

  • socket內核中,發送緩沖區中的可用字節數(發送緩沖區的空閑位置大小),大于等于低水位標記,SO_SNDLOWAT,此時可以無阻塞的寫,并且返回值大于0

  • socket的寫操作被關閉(close或者shutdown),對于一個寫操作被關閉的socket進行寫操作,會觸發SIGPIPE信號

  • socket使用非阻塞connect連接成功或失敗之后 socket上有未讀取的錯誤

  • 異常就緒

  • socket上收到帶外數據(關于帶外數據,和TCP緊急模式相關,在TCP報頭中有一個緊急指針的字段)

  • 4.poll的優點及缺點

poll的優點

  • 不同與select使用三個位圖來表示三個fdset的方式,poll使用一個pollfd的指針實現.pollfd結構包含了要監視的event和發生的event,不再使用select“參數-值”傳遞的方式. 接口使用比 select更方便.
  • poll并沒有最大數量限制 (但是數量過大后性能也是會下降).

poll的缺點

  • poll中監聽的文件描述符數目增多時 和select函數一樣,poll返回后,需要輪詢pollfd來獲取就緒的描述符.
  • 每次調用poll都需要把大量的pollfd結構從用戶態拷貝到內核中. 同時連接的大量客戶端在一時刻可能只有很少的處于就緒狀態,因此隨著監視的描述符數量的增長, 其效 率也會線性下降
  • 5.基于poll實現tcp服務器(多用戶)
#pragma once #include <functional> #include "tcp_socket.hpp" #include <poll.h> #include <unistd.h> #include <cstring> #include <vector> #include <string> #include <iostream>class Poll {public:Poll():fds_(nullptr),fds_size_(15),nfds_(0),timeout_(1000){fds_=new pollfd[fds_size_];}bool Add(TcpSocket& sock){if(nfds_== fds_size_){//需要擴容pollfd* new_fds = new pollfd[2 * fds_size_];memcpy(new_fds,fds_,fds_size_ * sizeof(pollfd));fds_size_ *= 2;delete[] fds_;fds_ = new_fds;}fds_[nfds_].fd = sock.GetFd();fds_[nfds_].events = POLLIN;++nfds_;return true;}bool Del(TcpSocket& sock){int del_fd = sock.GetFd();for(size_t i = 0;i < nfds_;++i){//在fds_內才移除if(fds_[i].fd == del_fd){fds_[i] = fds_[--nfds_];break;}}return true;}bool Wait(std::vector<TcpSocket>& list,int timeout = 1000){timeout_=timeout;int ret = poll(fds_,nfds_,timeout_);if(ret < 0){perror("Poll Wait");return false;}else if(ret == 0){std::cout<<"poll wait timeout"<<std::endl;return false;}for(nfds_t i = 0;i < nfds_;++i){if(fds_[i].revents == POLLIN){TcpSocket sock(fds_[i].fd);list.push_back(sock);}}return true;}int GetNfds(){return nfds_;}const pollfd* GetFds(){return fds_;}private:pollfd* fds_;nfds_t fds_size_;nfds_t nfds_;int timeout_; };typedef std::function<void(const std::string& req,std::string* resp)> Handler;class TcpPollServer {public:TcpPollServer(const std::string& ip,const uint16_t port):ip(ip),port(port){}~TcpPollServer(){_sock.Close();}bool Start(Handler handler){if(!_sock.Socket())return false;if(!_sock.Bind(ip,port))return false;if(!_sock.Listen())return false;Poll poll;poll.Add(_sock);while(1){std::vector<TcpSocket> list;if(!poll.Wait(list))continue;for(size_t i = 0;i < list.size();++i){if(list[i].GetFd() == _sock.GetFd()){TcpSocket NewSock;if(!_sock.Accept(&NewSock,NULL,NULL))continue;printf("客戶端已連接!~\n");poll.Add(NewSock);}else{std::string req;int n = list[i].Recv(&req);if(n == 0){poll.Del(list[i]);list[i].Close();continue;}else{std::cout<<"客戶端發送:"<<req<<std::endl;std::string resp;handler(req,&resp);list[i].Send(resp);}}}}return true;}private:TcpSocket _sock;std::string ip;uint16_t port; };

總結

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

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