亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

IO多路復用之poll全面總結(必看篇)

 更新時間:2016年12月24日 11:11:59   投稿:jingxian  
下面小編就為大家?guī)硪黄狪O多路復用之poll全面總結(必看篇)。小編覺得挺不錯的?,F(xiàn)在就分享給大家。也給大家做個參考。一起跟隨小編過來看看吧

1、基本知識

poll的機制與select類似,與select在本質(zhì)上沒有多大差別,管理多個描述符也是進行輪詢,根據(jù)描述符的狀態(tài)進行處理,但是poll沒有最大文件描述符數(shù)量的限制。poll和select同樣存在一個缺點就是,包含大量文件描述符的數(shù)組被整體復制于用戶態(tài)和內(nèi)核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨著文件描述符數(shù)量的增加而線性增大。

2、poll函數(shù)

函數(shù)格式如下所示:

# include <poll.h>
int poll ( struct pollfd * fds, unsigned int nfds, int timeout);

pollfd結構體定義如下:

struct pollfd {

int fd;     /* 文件描述符 */
short events;     /* 等待的事件 */
short revents;    /* 實際發(fā)生了的事件 */
} ; 

每一個pollfd結構體指定了一個被監(jiān)視的文件描述符,可以傳遞多個結構體,指示poll()監(jiān)視多個文件描述符。每個結構體的events域是監(jiān)視該文件描述符的事件掩碼,由用戶來設置這個域。revents域是文件描述符的操作結果事件掩碼,內(nèi)核在調(diào)用返回時設置這個域。events域中請求的任何事件都可能在revents域中返回。合法的事件如下:

POLLIN 有數(shù)據(jù)可讀。

POLLRDNORM   有普通數(shù)據(jù)可讀。

POLLRDBAND  有優(yōu)先數(shù)據(jù)可讀。

POLLPRI 有緊迫數(shù)據(jù)可讀。

POLLOUT      寫數(shù)據(jù)不會導致阻塞。

POLLWRNORM   寫普通數(shù)據(jù)不會導致阻塞。

POLLWRBAND    寫優(yōu)先數(shù)據(jù)不會導致阻塞。

POLLMSGSIGPOLL 消息可用。

此外,revents域中還可能返回下列事件:

POLLER   指定的文件描述符發(fā)生錯誤。

POLLHUP 指定的文件描述符掛起事件。

POLLNVAL指定的文件描述符非法。

這些事件在events域中無意義,因為它們在合適的時候總是會從revents中返回。

使用poll()和select()不一樣,你不需要顯式地請求異常情況報告。

POLLIN | POLLPRI等價于select()的讀事件,POLLOUT |POLLWRBAND等價于select()的寫事件。POLLIN等價于POLLRDNORM |POLLRDBAND,而POLLOUT則等價于POLLWRNORM。例如,要同時監(jiān)視一個文件描述符是否可讀和可寫,我們可以設置 events為POLLIN |POLLOUT。在poll返回時,我們可以檢查revents中的標志,對應于文件描述符請求的events結構體。如果POLLIN事件被設置,則文件描述符可以被讀取而不阻塞。如果POLLOUT被設置,則文件描述符可以寫入而不導致阻塞。這些標志并不是互斥的:它們可能被同時設置,表示這個文件描述符的讀取和寫入操作都會正常返回而不阻塞。

timeout參數(shù)指定等待的毫秒數(shù),無論I/O是否準備好,poll都會返回。timeout指定為負數(shù)值表示無限超時,使poll()一直掛起直到一個指定事件發(fā)生;timeout為0指示poll調(diào)用立即返回并列出準備好I/O的文件描述符,但并不等待其它的事件。這種情況下,poll()就像它的名字那樣,一旦選舉出來,立即返回。

返回值和錯誤代碼

成功時,poll()返回結構體中revents域不為0的文件描述符個數(shù);如果在超時前沒有任何事件發(fā)生,poll()返回0;失敗時,poll()返回-1,并設置errno為下列值之一:
EBADF       一個或多個結構體中指定的文件描述符無效。

EFAULTfds 指針指向的地址超出進程的地址空間。

EINTR  請求的事件之前產(chǎn)生一個信號,調(diào)用可以重新發(fā)起。

EINVALnfds參數(shù)超出PLIMIT_NOFILE值。

ENOMEM     可用內(nèi)存不足,無法完成請求。

3、測出程序

編寫一個echo server程序,功能是客戶端向服務器發(fā)送信息,服務器接收輸出并原樣發(fā)送回給客戶端,客戶端接收到輸出到終端。

服務器端程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <netinet/in.h>
#include <sys/socket.h>
#include <poll.h>
#include <unistd.h>
#include <sys/types.h>

#define IPADDRESS  "127.0.0.1"
#define PORT    8787
#define MAXLINE   1024
#define LISTENQ   5
#define OPEN_MAX  1000
#define INFTIM   -1

//函數(shù)聲明
//創(chuàng)建套接字并進行綁定
static int socket_bind(const char* ip,int port);
//IO多路復用poll
static void do_poll(int listenfd);
//處理多個連接
static void handle_connection(struct pollfd *connfds,int num);

int main(int argc,char *argv[])
{
  int listenfd,connfd,sockfd;
  struct sockaddr_in cliaddr;
  socklen_t cliaddrlen;
  listenfd = socket_bind(IPADDRESS,PORT);
  listen(listenfd,LISTENQ);
  do_poll(listenfd);
  return 0;
}

static int socket_bind(const char* ip,int port)
{
  int listenfd;
  struct sockaddr_in servaddr;
  listenfd = socket(AF_INET,SOCK_STREAM,0);
  if (listenfd == -1)
  {
    perror("socket error:");
    exit(1);
  }
  bzero(&servaddr,sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  inet_pton(AF_INET,ip,&servaddr.sin_addr);
  servaddr.sin_port = htons(port);
  if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1)
  {
    perror("bind error: ");
    exit(1);
  }
  return listenfd;
}

static void do_poll(int listenfd)
{
  int connfd,sockfd;
  struct sockaddr_in cliaddr;
  socklen_t cliaddrlen;
  struct pollfd clientfds[OPEN_MAX];
  int maxi;
  int i;
  int nready;
  //添加監(jiān)聽描述符
  clientfds[0].fd = listenfd;
  clientfds[0].events = POLLIN;
  //初始化客戶連接描述符
  for (i = 1;i < OPEN_MAX;i++)
    clientfds[i].fd = -1;
  maxi = 0;
  //循環(huán)處理
  for ( ; ; )
  {
    //獲取可用描述符的個數(shù)
    nready = poll(clientfds,maxi+1,INFTIM);
    if (nready == -1)
    {
      perror("poll error:");
      exit(1);
    }
    //測試監(jiān)聽描述符是否準備好
    if (clientfds[0].revents & POLLIN)
    {
      cliaddrlen = sizeof(cliaddr);
      //接受新的連接
      if ((connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen)) == -1)
      {
        if (errno == EINTR)
          continue;
        else
        {
          perror("accept error:");
          exit(1);
        }
      }
      fprintf(stdout,"accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
      //將新的連接描述符添加到數(shù)組中
      for (i = 1;i < OPEN_MAX;i++)
      {
        if (clientfds[i].fd < 0)
        {
          clientfds[i].fd = connfd;
          break;
        }
      }
      if (i == OPEN_MAX)
      {
        fprintf(stderr,"too many clients.\n");
        exit(1);
      }
      //將新的描述符添加到讀描述符集合中
      clientfds[i].events = POLLIN;
      //記錄客戶連接套接字的個數(shù)
      maxi = (i > maxi ? i : maxi);
      if (--nready <= 0)
        continue;
    }
    //處理客戶連接
    handle_connection(clientfds,maxi);
  }
}

static void handle_connection(struct pollfd *connfds,int num)
{
  int i,n;
  char buf[MAXLINE];
  memset(buf,0,MAXLINE);
  for (i = 1;i <= num;i++)
  {
    if (connfds[i].fd < 0)
      continue;
    //測試客戶描述符是否準備好
    if (connfds[i].revents & POLLIN)
    {
      //接收客戶端發(fā)送的信息
      n = read(connfds[i].fd,buf,MAXLINE);
      if (n == 0)
      {
        close(connfds[i].fd);
        connfds[i].fd = -1;
        continue;
      }
      // printf("read msg is: ");
      write(STDOUT_FILENO,buf,n);
      //向客戶端發(fā)送buf
      write(connfds[i].fd,buf,n);
    }
  }
}

客戶端代碼如下所示:

#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>

#define MAXLINE   1024
#define IPADDRESS  "127.0.0.1"
#define SERV_PORT  8787

#define max(a,b) (a > b) ? a : b

static void handle_connection(int sockfd);

int main(int argc,char *argv[])
{
  int         sockfd;
  struct sockaddr_in servaddr;
  sockfd = socket(AF_INET,SOCK_STREAM,0);
  bzero(&servaddr,sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(SERV_PORT);
  inet_pton(AF_INET,IPADDRESS,&servaddr.sin_addr);
  connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
  //處理連接描述符
  handle_connection(sockfd);
  return 0;
}

static void handle_connection(int sockfd)
{
  char  sendline[MAXLINE],recvline[MAXLINE];
  int   maxfdp,stdineof;
  struct pollfd pfds[2];
  int n;
  //添加連接描述符
  pfds[0].fd = sockfd;
  pfds[0].events = POLLIN;
  //添加標準輸入描述符
  pfds[1].fd = STDIN_FILENO;
  pfds[1].events = POLLIN;
  for (; ;)
  {
    poll(pfds,2,-1);
    if (pfds[0].revents & POLLIN)
    {
      n = read(sockfd,recvline,MAXLINE);
      if (n == 0)
      {
          fprintf(stderr,"client: server is closed.\n");
          close(sockfd);
      }
      write(STDOUT_FILENO,recvline,n);
    }
    //測試標準輸入是否準備好
    if (pfds[1].revents & POLLIN)
    {
      n = read(STDIN_FILENO,sendline,MAXLINE);
      if (n == 0)
      {
        shutdown(sockfd,SHUT_WR);
    continue;
      }
      write(sockfd,sendline,n);
    }
  }
}

4、程序測試結果

以上就是小編為大家?guī)淼腎O多路復用之poll全面總結(必看篇)全部內(nèi)容了,希望大家多多支持腳本之家~

相關文章

  • CentOS 7下配置ntp服務的方法教程

    CentOS 7下配置ntp服務的方法教程

    網(wǎng)絡時間協(xié)議(NTP)用來同步網(wǎng)絡上不同主機的系統(tǒng)時間。你管理的所有主機都可以和一個指定的被稱為 NTP 服務器的時間服務器同步它們的時間。這篇文章主要給大家介紹了在CentOS 7下配置ntp服務并開啟開機自動啟動的方法教程,需要的朋友可以參考下。
    2017-05-05
  • linux中普通用戶的定時任務詳解

    linux中普通用戶的定時任務詳解

    這篇文章主要給大家介紹了關于linux中普通用戶的定時任務的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用linux具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04
  • 學習在kernel態(tài)下使用NEON對算法進行加速的方法

    學習在kernel態(tài)下使用NEON對算法進行加速的方法

    這篇文章主要介紹了學習在kernel態(tài)下使用NEON對算法進行加速的方法,一起來學習下,大大提高數(shù)據(jù)運算的效率。
    2017-11-11
  • Linux下Apache HTTP Server 2.4.26安裝教程

    Linux下Apache HTTP Server 2.4.26安裝教程

    這篇文章主要為大家詳細介紹了Linux下Apache HTTP Server 2.4.26的安裝,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 幫助你排序文本文件的 Awk 命令行或腳本(推薦)

    幫助你排序文本文件的 Awk 命令行或腳本(推薦)

    Awk 是個普遍存在的 Unix 命令,用于掃描和處理包含可預測模式的文本。這篇文章主要介紹了Awk 命令行或腳本的相關知識,需要的朋友可以參考下
    2019-12-12
  • 詳解從Linux源碼看Socket(TCP)的bind

    詳解從Linux源碼看Socket(TCP)的bind

    本文從Linux源碼的角度看Server端的Socket在進行bind的時候到底做了哪些事情(基于Linux 3.10內(nèi)核)
    2021-06-06
  • 詳解SSH如何配置key免密碼登錄

    詳解SSH如何配置key免密碼登錄

    這篇文章主要介紹了詳解SSH如何配置key免密碼登錄的相關資料,文中介紹的非常詳細,對大家的學習或者工作具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-03-03
  • 淺談Linux環(huán)境變量文件介紹

    淺談Linux環(huán)境變量文件介紹

    這篇文章主要介紹了淺談Linux環(huán)境變量文件介紹,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • CentOS 6.5上編譯安裝Apache服務器的方法(最小化安裝)

    CentOS 6.5上編譯安裝Apache服務器的方法(最小化安裝)

    這篇文章主要介紹了CentOS 6.5上編譯安裝Apache服務器的方法(最小化安裝),需要的朋友可以參考下
    2017-09-09
  • Linux下誤刪messages文件的找回方法

    Linux下誤刪messages文件的找回方法

    今天小編就為大家分享一篇關于Linux下誤刪messages文件的找回方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02

最新評論