久久婷婷香蕉热狠狠综合,精品无码国产自产拍在线观看蜜,寡妇房东在做爰3,中文字幕日本人妻久久久免费,国产成人精品三上悠亚久久

Hi,歡迎來到嵌入式培訓高端品牌 - 華清遠見教育科技集團<北京總部官網>,專注嵌入式工程師培養15年!
當前位置: > 華清遠見教育科技集團 > 嵌入式學習 > 講師博文 > 多路復用select與poll
多路復用select與poll
時間:2017-01-04作者:華清遠見

在UNIX/linux中有4中IO模型,分別為:
        1、 阻塞IO
        2、 非阻塞IO
        3、 IO多路復用
  &nbsp;     4、 信號驅動IO

這幾種IO模(mo)型(xing)(xing)(xing),阻(zu)塞(sai)IO是(shi)長用(yong)到(dao)的(de)(de)(de),并且操(cao)作相對簡單,但是(shi)缺點(dian)在(zai)于效(xiao)率低下,尤其是(shi)在(zai),同(tong)時(shi)操(cao)作多個IO的(de)(de)(de)時(shi)候(hou),不能隨時(shi)的(de)(de)(de)處理各個IO操(cao)作。而(er)非(fei)阻(zu)塞(sai)IO可以解決這個問(wen)題(ti),但是(shi)同(tong)樣也存(cun)在(zai)的(de)(de)(de)問(wen)題(ti),因為(wei)使用(yong)非(fei)阻(zu)塞(sai)IO模(mo)型(xing)(xing)(xing)的(de)(de)(de)時(shi)候(hou),就需要對每個IO操(cao)作進行輪訓(xun)操(cao)作,而(er)實際上輪空的(de)(de)(de)幾率是(shi)很(hen)大的(de)(de)(de),多以非(fei)阻(zu)塞(sai)IO模(mo)型(xing)(xing)(xing)是(shi)在(zai)那(nei)種輪空幾率相對較小(xiao)的(de)(de)(de)的(de)(de)(de)時(shi)候(hou)才會使用(yong)。因為(wei)輪訓(xun)是(shi)會占用(yong)相當多的(de)(de)(de)cpu時(shi)間片的(de)(de)(de)。基于這種考慮多路復用(yong)模(mo)型(xing)(xing)(xing)變產生了。

多路復(fu)用(yong)模型(xing)是(shi)對多個(ge)(ge)IO操(cao)作進(jin)行檢(jian)測,返回可操(cao)作集(ji)合,這樣(yang)就(jiu)(jiu)可以對其進(jin)行操(cao)作了。這樣(yang)就(jiu)(jiu)避(bi)免了阻(zu)塞IO不(bu)能隨時(shi)處(chu)理各個(ge)(ge)IO和(he)非阻(zu)塞占(zhan)用(yong)系(xi)統資源(yuan)的確定。下(xia)面就(jiu)(jiu)多路復(fu)用(yong)中兩(liang)個(ge)(ge)常用(yong)的系(xi)統調用(yong)select和(he)poll進(jin)行簡(jian)單的說明。

1、 select

select函數(shu)的原(yuan)型為:

#include <sys/select.h>
        #include <sys/time.h>
        #include <sys/types.h>
        #include <unistd.h>
        int select(int nfds,
                fd_set *readfds, 
                fd_set *writefds,
                fd_set *exceptfds, 
   &nbsp;      &nbsp;     struct timeval *timeout);

select的使用需要維護三類文件描述符集合,分別是:
        readfds:用于存放我們要檢測的可讀的文件描述符。
        writefds:用于存放我們要檢測的可寫的文件描述符。
        exceptfds:用于存放我們(men)要檢(jian)測的是(shi)否發生異常的文件描述符。

在使用(yong)select的時候需要注意,在調用(yong)select后(hou)者幾個集(ji)(ji)合(he)就會(hui)變化,變為是操作的集(ji)(ji)合(he),即可讀寫或發生(sheng)異常,所以(yi)在調用(yong)select之前需要保存以(yi)前的集(ji)(ji)合(he)。

系統(tong)為我們提供了下面四(si)個宏來操作這些(xie)文件(jian)描(miao)述符集(ji)合:

void FD_SET(int fd, fd_set *set);
        void FD_CLR(int fd, fd_set *set);
        I int FD_ISSET(int fd, fd_set *set);
        void FD_ZERO(fd_set *set);

其中FD_SET用來將(jiang)一個文(wen)件描(miao)述符加入到文(wen)件描(miao)述符集(ji)合里,FD_CLR是(shi)(shi)刪除,FD_ISSET是(shi)(shi)判斷(duan)文(wen)件描(miao)述符是(shi)(shi)否在(zai)這個集(ji)合里,而FD_ZERO是(shi)(shi)將(jiang)這個集(ji)合清零。

下面我們以一個(ge)簡(jian)單的例子來(lai)說明(ming)select的使(shi)用。

#include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <string.h>
        #include <sys/types.h>
        #include <sys/select.h>
        #include <sys/socket.h>
        #include <netinet/in.h>
  &nbsp;    &nbsp;#include <arpa/inet.h>

#define N 64

int main(int argc, char *argv[])
        {
                if(argc != 2)
                {
                        printf(“format: server <server ip> <server port>”);
                        exit(0);
                }
                int i, servsock, connfd, maxfd;
                char buf[N];
        &nbsp;       fd_set rdfd,rdfd1;

         struct sockaddr_in servaddr;

        if((servsock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
                {
                        perror("socket");
                        exit(1);
               &nbsp;}

        memset(&servaddr, 0, sizeof(servaddr));
                servaddr.sin_family = PF_INET;
                servaddr.sin_addr.s_addr = inet_addr("192.168.1.203");
       ;       ;  servaddr.sin_port = htons(8889);

        if(bind(servsock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
                {
                        perror("bind");
                        exit(1);
         &nbsp;      }

        listen(servsock, 5);
                maxfd = servsock;

                FD_ZERO(&rdfd1);
                FD_SET(0, &rdfd1);
     &nbsp;          FD_SET(servsock, &amp;rdfd1);

        for(;;)
                {

                        rdfd = rdfd1;
                        if(select(maxfd+1, &rdfd, NULL, NULL, NULL) < 0)
                        {
                                perror("select");
                                exit(1);
      &nbsp;                 }

                for(i = 0; i <= maxfd; i++)
                        {
                                if(FD_ISSET(i, &rdfd))
                                {
                                        if( i == STDIN_FILENO)
                                        {
                                                fgets(buf, N, stdin);
                                                printf("%s", buf);
                                        }
                                        else if(i == servsock)
                                        {
                                                connfd = accept(servsock, NULL, NULL);
                                                printf("New Connection %d is comming\n", connfd);
                                                send(connfd, buf, strlen(buf), 0);
                                                sleep(1);
                                                close(connfd);
                                        }
                                }
                        }
           ;     }

        return 0;
   &nbsp;    }

上面這(zhe)段(duan)程序在select會(hui)阻塞,這(zhe)個時(shi)候我們可以(yi)定義一個時(shi)間結構體(ti)變量,如(ru)下:

struct timeval timeout;
        timeval的原型為:
        struct timeval {
                                long        tv_sec;        /* seconds */
                                long        tv_usec;        /* microseconds */
    &nbsp;   };

這(zhe)個(ge)變量可(ke)以提供一個(ge)微秒級的時間,我(wo)們(men)可(ke)以使用(yong)這(zhe)個(ge)作為超時處(chu)理。使用(yong)方(fang)式就是把(ba)這(zhe)個(ge)變量作為select系(xi)統調用(yong)的后一個(ge)參數。

2、 poll

poll的原型為:

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

poll的(de)使用(yong)不(bu)需(xu)(xu)要分別維護幾個(ge)(ge)表,只需(xu)(xu)要維護一個(ge)(ge)結(jie)構體(ti)數(shu)組,這個(ge)(ge)結(jie)構體(ti)為:

struct pollfd {
                                int        fd;        /* file descriptor */
                                short events;        /* requested events */
                                short revents;        /* returned events */
        };

這個結構體(ti)幾個成(cheng)員(yuan)分(fen)別是我們要監測的(de)文件描述(shu)符,和我們請求的(de)事(shi)件及后返回的(de)事(shi)件。

poll事件(jian)的類型為:

POLLIN There is data to read.
        POLLPRI There is urgent data to read .
        POLLOUT Writing now will not block.
        POLLERR Error condition (output only).
        POLLHUP Hang up (output only).
 &nbsp;      POLLNVAL Invalid request: fd not open (output only).

上面這(zhe)些事(shi)件下面三種在events中(zhong)沒有用的,只能(neng)在revents中(zhong)才能(neng)出現。我們可以調用poll并且查看每個文件描述符的返回狀態進(jin)行相應(ying)的操作。

下面以一個簡(jian)單的實力說明poll的使用:

#include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <poll.h>
        #include <sys/socket.h>
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <sys/types.h>
        #include <errno.h>
   &nbsp;    #include <string.h>

#define OPEN_MAX openmax
  &nbsp;     #define BUFSIZE 1024

int main(int argc, char **argv)
        {
                if(argc != 3)
                {
                        printf("format: server-poll <server ip> <port>");
                        exit(0);
 ;               }

        int openmax = getdtablesize();

        int listensock, connsock;
                struct sockaddr_in servaddr;
                struct pollfd fds[OPEN_MAX];
                int i, count = 0, ready, reval;
       ; ;        char readbuf[BUFSIZE];

        for(i = 0; i < OPEN_MAX; i++)
                {
                        fds[i].fd = -1;
 &nbsp;     &nbsp;        }

        if((listensock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
                {
                        perror("socket");
                        exit(0);
       &nbsp;        }

        memset(&servaddr, 0, sizeof(servaddr));
                servaddr.sin_family = AF_INET;
                servaddr.sin_addr.s_addr = inet_addr(argv[1]);
           ;     servaddr.sin_port = htons(atoi(argv[2]));

        if(bind(listensock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
                {
                        perror("bind");
                        exit(1);
 ;      &nbsp;        }

       &nbsp;listen(listensock, 5);

        fds[0].fd = 0;
                fds[0].events = POLLIN;
                count++;
                fds[1].fd = listensock;
                fds[1].events = POLLIN;
                count++;

                for(;;)
                {
                        memset(readbuf, 0, BUFSIZE);
                        ready = poll(fds, count, 0);
                        for(i = 0; i < count; i++)
                        {
                                if(fds[i].revents & POLLIN)
                                {
                                        if(fds[i].fd == 0)
                                        {
                                                fgets(readbuf, BUFSIZE, stdin);
                                                printf("read buf:%s\n", readbuf);
                                        }
                                        else if(fds[i].fd == listensock)
                                        {
                                                connsock = accept(listensock, NULL, NULL);
                                                printf("client connect\n");
                                                fds[count].fd = connsock;
                                                fds[count].events = POLLIN;
                                                count++;
                                                }
                                                else
                                                {
                                                        reval = recv(fds[i].fd, readbuf, BUFSIZE, 0);
                                                        printf("recv buf:%s\n", readbuf);
                                                        send(fds[i].fd, readbuf, reval, 0);
                                                }
                                        }
                                }
                       }
                }
                return 0;
  &nbsp;     }

發表評論
評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)