溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

poll實現(xiàn)IO復(fù)用,TCP通信

發(fā)布時間:2020-08-06 14:36:22 來源:網(wǎng)絡(luò) 閱讀:893 作者:小止1995 欄目:編程語言

函數(shù)原型:

poll實現(xiàn)IO復(fù)用,TCP通信

函數(shù)說明:該函數(shù)允許進(jìn)程指示內(nèi)核等待多個事件中的任何一個發(fā)生,并只在有一個或多個事件發(fā)生或經(jīng)歷一段指定的時間后才喚醒它。

參數(shù)說明:

poll實現(xiàn)IO復(fù)用,TCP通信

fds:是一個struct pollfd結(jié)構(gòu)類型的數(shù)組,用于存放需要檢測其狀態(tài)的Socket描述符;

每當(dāng)調(diào)用這個函數(shù)之后,系統(tǒng)不會清空這個數(shù)組,操作起來比較方便;特別是對于socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點與select()函數(shù)不同,調(diào)用select()函數(shù)之后,select()函數(shù)會清空它所檢測的socket描述符集合,導(dǎo)致每次調(diào)用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數(shù)適合于只檢測一個socket描述符的情況,而poll()函數(shù)適合于大量socket描述符的情況;

nfds:nfds_t類型的參數(shù),用于標(biāo)記數(shù)組fds中的結(jié)構(gòu)體元素的總數(shù)量;

timeout:是poll函數(shù)阻塞的時間,單位:毫秒;

  1. 如果timeout==0,那么poll() 函數(shù)立即返回而不阻塞

  2. 如果timeout==INFTIM,即負(fù)數(shù),那么poll() 函數(shù)會一直阻塞下去,直到所檢測的socket描述符上的感興趣的事件發(fā)生是才返回,如果感興趣的事件永遠(yuǎn)不發(fā)生,那么poll()就會永遠(yuǎn)阻塞下去;

  3. poll()函數(shù)會以輪詢方式在timeout所指定的毫秒時間長度之后返回

返回值:

>0:數(shù)組fds中準(zhǔn)備好讀、寫或出錯狀態(tài)的那些socket描述符的總數(shù)量;

==0:數(shù)組fds中沒有任何socket描述符準(zhǔn)備好讀、寫,或出錯;此時poll超時,超時時間是timeout毫秒

-1: poll函數(shù)調(diào)用失敗,同時會自動設(shè)置全局變量errno;

struct pollfd中event的設(shè)置參數(shù):


poll實現(xiàn)IO復(fù)用,TCP通信

實現(xiàn)IO復(fù)用:關(guān)心輸入輸出條件就緒

#include<stdio.h>                                                               
#include<stdlib.h>
#include<string.h>
#include<poll.h>
int main()
{
    struct pollfd fds[2];
    fds[0].fd=0;
    fds[0].events=POLLIN;
    fds[0].revents=0;

    fds[1].fd=1;
    fds[1].events=POLLOUT;
    fds[1].revents=0;
    char buf[1024];
    ssize_t _s;
    int i=0;
    int timeout=5000;
    while(1)
    {
        timeout=5000;
        switch(poll(fds,2,timeout))
        {
            case -1://error
                perror("poll");
                break;
            case 0://timeout
                printf("time out\n");
                break;
            default:
            {
                for(i=0;i<2;++i)
                {
                    if(fds[i].fd==0&&fds[i].revents&POLLIN)
                    {
                        _s=read(0,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            if(strncmp(buf,"quit",4)==0)
                            {
                                close(fds[i].fd);
                                exit(0);
                            }
                            printf("echo:%s",buf);
                        } 
                        //fds[i].revents=0;//not need
                    }
                //  else if(fds[i].fd==1&&fds[i].revents&&POLLOUT)
                //  {
                //      strcpy(buf,"hello");
                //      printf("echo: %s",buf);
                //      fds[i].revents=0;//not need
                //  }
                }
            }
            break;
        }
    }
    return 0;
}

運行截圖:

poll實現(xiàn)IO復(fù)用,TCP通信

TCP通信:監(jiān)聽socket

server:

  1. 創(chuàng)建監(jiān)聽套接字并初始化:調(diào)用socket,bind,listen,唯一描述符是監(jiān)聽描述符初始化數(shù)據(jù)結(jié)構(gòu)。

  2. 阻塞于select:select等待某個事件發(fā)生或新客戶連接的建立或是數(shù)據(jù),F(xiàn)IN或RST的到達(dá)。

  3. accept新連接

     如果監(jiān)聽套接字變?yōu)榭勺x,那么已建立一個新的連接,我們調(diào)用accept并更新相應(yīng)數(shù)據(jù)結(jié)構(gòu)。使用fds數(shù)組中第一個未用項記錄這個已連接描述符。

  4. 檢查現(xiàn)有連接

 對于每個現(xiàn)有客戶連接,我們要測試其描述符是否在select返回描述符集中,如果是就從該客戶讀取一行文本,并回顯,輸出。如果該客戶關(guān)閉了連接,那么read將返回0,更新數(shù)據(jù)結(jié)構(gòu)。

poll與select不同在于描述符存儲方式不同和參數(shù)類型不同。

1.結(jié)構(gòu)體數(shù)組的管理:當(dāng)每次有需要關(guān)心的描述符時,將其放入結(jié)構(gòu)體中,每次有無效的描述符后,將其描述符置-1,下次poll函數(shù)會忽略它。當(dāng)有新的描述符加入時,從頭遍歷結(jié)構(gòu)體,將為-1的元素設(shè)為要關(guān)心的描述符事件狀態(tài)。切記:當(dāng)新的描述符加到結(jié)構(gòu)體數(shù)組末尾時要更新關(guān)心描述符個數(shù),即poll第二個參數(shù)。

2.每次調(diào)用poll后,結(jié)構(gòu)體元素revents會存儲就緒事件狀態(tài),當(dāng)每次重新調(diào)用poll之前時,系統(tǒng)會自己設(shè)置其為0,重新監(jiān)聽關(guān)心事件(不需要用戶重新置0)

3.poll中參數(shù)不是輸入,輸出型,因此timeout,struct pollfd *fds參數(shù)不需重置,nfds看情況(參照第一點),而select函數(shù)是輸入輸出類型,每次調(diào)用前需重置。

//server:最終版
include<stdio.h>                                                                        
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<poll.h>
#include<string.h>
#include<errno.h>
#define _BACKLOG_ 5
#define _SIZE_ 64
static void usage(const char* proc)
{
    printf("%s [ip][port]\n",proc);
}
static int start(char* ip,int port)
{
    //1.create a socket
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket");
        exit(1);
    }
    //2.bind
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(port);
    local.sin_addr.s_addr=inet_addr(ip);
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind");
        exit(2);
    }
    //3.set listen  state
    if(listen(sock,_BACKLOG_)<0)
    {
        perror("listen");
        exit(3);
    }
    return sock;
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {       
        usage(argv[0]);
        return 1;
    }
    int _port=atoi(argv[2]);
    char* _ip=argv[1];
    //listen_sock_fd
    int listen_sock=start(_ip,_port);
    struct  pollfd  polls[_SIZE_];//struct pollfd arrays
    int index=0;//effective fdnum
    int timeout=5000;//millseconds
    int i=0;//index
    polls[0].fd=listen_sock;
    polls[0].events=POLLIN;
    polls[0].revents=0;
    int max_num=1;
    for(i=1;i<_SIZE_;++i)
    {
        polls[i].fd=-1;
    }
    char buf[1024];
    ssize_t _s=0;
    struct sockaddr_in remote;//accept
    socklen_t len=sizeof(remote);                              
    while(1)
    {
        //new start
        //timeout=5000;
        switch(poll(polls,max_num,timeout))
        {
            case 0://timeout
                printf("time out...\n");
                break;
            case -1://error
                perror("poll");
                break;
            default://normal
            {
                for(i=0;i<max_num;++i)
                {
                    if(polls[i].fd==listen_sock&&(polls[i].revents&\
                        POLLIN))
                    {
                        printf("get a connect\n");
                        int new_sock=accept(listen_sock,\
                        (struct sockaddr*)&remote,&len);
                        if(new_sock<0)                    
                        {
                            perror("accept");
                            continue;
                        }
                        int j=1;//0 is listensock
                        for(;j<_SIZE_;++j)
                         {
                             if(polls[j].fd==-1)
                             {
                                 polls[j].fd=new_sock;
                                 polls[j].events=POLLIN;
                                 polls[j].revents=0;
                                 break;
                             }
                         }
                        if(j==_SIZE_)
                        {
                            printf("full");
                            close(new_sock);
                            return -1;
                        }
                        if(j==max_num)//加入的是max_num為下標(biāo)的位置,即最后
                            max_num+=1;                   
                    }
                    else if(polls[i].fd>0&&(polls[i].revents&\
                        POLLIN))//read ready
                    {
                        _s=read(polls[i].fd,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            printf("client: %s",buf);
                            write(polls[i].fd,buf,strlen(buf));         
                            polls[i].revents=0;//not need
                        }
                        else if(_s==0)//client close
                        {
                            close(polls[i].fd);
                            polls[i].fd=-1;
                            printf("client is close\n");
                        }
                    }
                    else
                    {}
                }
            } 
            break;
        }
    }
    for(i=0;i<_SIZE_;++i)
    {
        if(polls[i].fd!=-1)
            close(polls[i].fd);
    }
    return 0;
}                                                                          
                                                              
//server:優(yōu)質(zhì)版
#include<stdio.h>                                                       
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<poll.h>
#include<string.h>
#include<errno.h>
#define _BACKLOG_ 5
#define _SIZE_ 64
static void usage(const char* proc)
{
    printf("%s [ip][port]\n",proc);
}
static int start(char* ip,int port)
{
    //1.create a socket
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket");
        exit(1);
    }
    //2.bind
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(port);
    local.sin_addr.s_addr=inet_addr(ip);
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind");
        exit(2);
    }
    //3.set listen  state
    if(listen(sock,_BACKLOG_)<0)
    {
        perror("listen");
        exit(3);           
    }
    return sock;
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
        return 1;
    }
    int _port=atoi(argv[2]);
    char* _ip=argv[1];
    //listen_sock_fd
    int listen_sock=start(_ip,_port);
    struct  pollfd  polls[_SIZE_];//struct pollfd arrays
    int index=0;//effective fdnum
    int timeout=5000;//millseconds
    int i=0;//index
    polls[0].fd=listen_sock;
    polls[0].events=POLLIN;
    polls[0].revents=0;
    ++index;
    for(i=1;i<_SIZE_;++i)
    {
        polls[i].fd=-1;    
    }
    char buf[1024];
    ssize_t _s=0;
    struct sockaddr_in remote;//accept
    socklen_t len=sizeof(remote);
    while(1)
    {
        //new start
        timeout=5000;
        int j=index;
        i=0;
        //消除struct pollfd中已不關(guān)心的描述符:前移,得到有效的最后一個元素下標(biāo)
        while(i<j)
        {
            while(i<j&&polls[i].fd!=-1)//從前面數(shù)第一個無效的
                ++i;
            while(i<j&&polls[j].fd==-1)//從后面數(shù)第一個有效的
                --j;
            if(i<j)//復(fù)制fd
            {
                polls[i].fd=polls[j].fd;
                polls[i].events=POLLIN;//可不需要,因為event參數(shù)不發(fā)生變化,本程序只監(jiān)聽讀事件
                polls[index].revents=0;
            }                             
        }
        index=i;
        //printf("%d",index);
        //須保證polls是有序的
        switch(poll(polls,index,timeout))//index表明最后一個關(guān)心的描述符在數(shù)組中下標(biāo)+1=個數(shù)
        {
            case 0://timeout
                printf("time out...\n");
                break;
            case -1://error
                perror("poll");
                break;
            default://normal
            {
                for(i=0;i<index;++i)
                {
                    if(polls[i].fd==listen_sock&&(polls[i].revents&\
                        POLLIN))
                    {
                        printf("get a connect\n");
                        int new_sock=accept(listen_sock,\
                        (struct sockaddr*)&remote,&len);
                        if(new_sock<0)
                        {      
                            perror("accept");
                            continue;
                        }
                        if(index==_SIZE_)
                        {
                            printf("full");
                            close(new_sock);
                            return -1;
                        }
                        polls[index].fd=new_sock;
                        polls[index].events=POLLIN;
                        polls[index].revents=0;
                        ++index;
                    }
                    else if(polls[i].fd>0&&(polls[i].revents&\
                        POLLIN))//read ready
                    {
                        _s=read(polls[i].fd,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            printf("client: %s",buf);
                            write(polls[i].fd,buf,strlen(buf));   
                            polls[i].revents=0;
                        }
                        else if(_s==0)//client close
                        {
                            close(polls[i].fd);
                            polls[i].fd=-1;
                            printf("client is close\n");
                        }
                    }
                    else
                    {}
                }
            }
            break;
        }
    }
    for(i=0;i<_SIZE_;++i)
    {
        if(polls[i].fd!=-1)
            close(polls[i].fd);
    }
    return 0;
} 
//仿select版,用輔助數(shù)組存儲,沒有利用poll結(jié)構(gòu)體的優(yōu)點,event不清空,開銷大                                                              
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
        return 1;
    }
    int _port=atoi(argv[2]);
    char* _ip=argv[1];
    //listen_sock_fd
    int listen_sock=start(_ip,_port);
    struct  pollfd  polls[_SIZE_];//struct pollfd arrays
    int index=0;//effective fdnum
    int timeout=5000;//millseconds
    int i=0;//index
    int fds[_SIZE_];
    fds[0]=listen_sock;  
    for(i=1;i<_SIZE_;++i)
    {
        fds[i]=-1;
    }
    char buf[1024];
    ssize_t _s=0;
    struct sockaddr_in remote;//accept
    socklen_t len=sizeof(remote);
    while(1)
    {
        index=0;//new start
        timeout=5000;
        for(i=0;i<_SIZE_;++i)
        {
            polls[i].fd=-1;
        }
        for(i=0;i<_SIZE_;++i)
        {
            if(fds[i]!=-1)
            {                  
                polls[index].fd=fds[i];
                polls[index].events=POLLIN;
                polls[index].revents=0;
                ++index;
            }
        }
        switch(poll(polls,index,timeout))
        {
            case 0://timeout
                printf("time out...\n");
                break;
            case -1://error
                perror("poll");
                break;
            default://normal
            {
                for(i=0;i<index;++i)
                {
                    if(polls[i].fd==listen_sock&&(polls[i].revents&\
                        POLLIN))         
                    {
                        printf("get a connect\n");
                        int new_sock=accept(listen_sock,\
                        (struct sockaddr*)&remote,&len);
                        if(new_sock<0)
                        {
                            perror("accept");
                            continue;
                        }
                        int j;
                        for(j=0;j<_SIZE_;++j)
                        {
                            if(fds[j]==-1)
                            {
                                fds[j]=new_sock;
                                break;
                            }
                        }
                        if(j==_SIZE_)
                        {                         
                            printf("full");
                            close(new_sock);
                            return -1;
                        }
                        polls[i].revents=0;//reset
                    }
                    else if(polls[i].fd>0&&(polls[i].revents&\
                        POLLIN))//read ready
                    {
                        _s=read(polls[i].fd,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            printf("client: %s",buf);
                            write(polls[i].fd,buf,strlen(buf));
                        }
                        else if(_s==0)//client close
                        {
                            close(polls[i].fd);
                            int j;                     
                            for(j=0;j<_SIZE_;++j)
                            {
                                if(fds[j]==polls[i].fd)
                                {
                                    fds[j]=-1;
                                    break;
                                }
                            }
                            printf("client is close\n");
                        }
                    }
                    else
                    {}
                }
            }
            break;
        }
    }
    for(i=0;i<_SIZE_;++i)
    {                           
            if(fds[i]!=-1)
            close(fds[i]);
    }
    return 0;
}          
//client:
#include<stdio.h>                                                       
#include<stdlib.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
void Usage(const char* proc)
{
    printf("%s [ip][port]",proc);
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        return 1;
    }
    int client_sock=socket(AF_INET,SOCK_STREAM,0);
    if(client_sock<0)
    {
        perror("socket");
        return 1;
    }
    struct sockaddr_in client;
    client.sin_family=AF_INET;
    client.sin_port=htons(atoi(argv[2]));
    client.sin_addr.s_addr=inet_addr(argv[1]);
    char buf[1024];
    ssize_t _s;
    if(connect(client_sock,(struct sockaddr*)&client,sizeof(client))<0)
    {
        perror("connection");
        return 2;
    }
    while(1)
    {
        printf("please enter:\n");
        _s=read(0,buf,sizeof(buf)-1);        
        if(_s>0)
            buf[_s]='\0';
        if(strncmp(buf,"quit",4)==0)
        {
            printf("client is quit\n");
            break;
        }
        write(client_sock,buf,_s);
        _s=read(client_sock,buf,sizeof(buf)-1);
        if(_s>0)
        {
            buf[_s]='\0';
            printf("server->client: %s",buf);
        }
    }
    close(client_sock);

    return 0;
}

運行截圖:

poll實現(xiàn)IO復(fù)用,TCP通信

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI