I/O多重化select

5240 ワード

select関数定義
#include
#include
int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)
戻り値:準備記述子の数、タイムアウトは0、エラーは-1を返します.
パラメータの説明:
(1)第1のパラメータmaxfdp 1は、テスト対象の記述文字数を指定し、その値は、テスト対象の最大記述文字に1を加える(したがって、このパラメータをmaxfdp 1と命名する)、記述文字0、1、2...maxfdp 1-1は、ファイル記述子が0から始まるため、テストされます.(2)中間の3つのパラメータreadset,writeset,exceptsetは,カーネルに読み取り,書き込み,異常条件をテストさせる記述語を指定する.ある条件に興味がなければ、空のポインタに設定できます.struct fd_setは、ファイル記述子が格納されたセットとして理解でき、void FD_の4つのマクロで設定できます.ZERO(fd_set *fdset);//クリア集合void FD_SET(int fd, fd_set *fdset);//指定されたファイル記述子をセットに追加void FD_CLR(int fd, fd_set *fdset);//指定されたファイル記述子をセットからint FDを削除するISSET(int fd, fd_set *fdset);//セットで指定したファイル記述子が読み書きできるかどうかを確認します(3)timeoutは、指定した記述語のいずれかの準備がどれだけ時間がかかるかをカーネルに通知します.そのtimeval構造は、この時間の秒数とマイクロ秒数を指定するために使用されます.         struct timeval                    long tv_sec;  //seconds                    long tv_usec;  //microseconds        }; このパラメータには,(1)I/Oの準備ができている記述語が1つある場合にのみ戻る,(3)常に待つ可能性がある.このため、このパラメータを空ポインタNULLに設定します.(2)一定時間待機:記述語がI/Oの準備ができているときに戻るが、このパラメータによって指定されたtimeval構造で指定された秒数とマイクロ秒数を超えない.(3)まったく待たない:記述語をチェックしてすぐに戻ることをポーリングと呼ぶ.このため、パラメータはtimeval構造を指し、タイマ値は0でなければなりません.
selectの欠点:
(1)selectを呼び出すたびに,fd集合をユーザ状態からカーネル状態にコピーする必要があり,このオーバーヘッドはfdが多い場合に大きくなる.
(2)同時にselectを呼び出すたびにカーネルが伝達するすべてのfdを遍歴する必要があり,このオーバーヘッドはfdが多い場合でも大きい.
(3)selectでサポートされているファイル記述子の数が小さすぎて、デフォルトは1024です.
selectサービス側プログラム:
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include  


#define LISTENQ      1024
#define SERVPORT     7885
#define MAXLINE      4096

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr, cliaddr;
    int listenfd, connfd;
    fd_set allset, rset;
    int result;
    socklen_t client_len;

    ssize_t n;                          //read() 
    char buf[MAXLINE];

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if(listenfd  == -1)
    {
        perror("create socket error");
        return -1;
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERVPORT);
    inet_pton(AF_INET, "INADDR_ANY", &servaddr.sin_addr);


    //   
    int on =1;
    if((setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)  
    {  
        perror("setsockopt failed");  
        exit(EXIT_FAILURE);  
    }  
    
    if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        perror("bind the socket");
        return -1;
    }

    if(listen(listenfd, LISTENQ) == -1)
    {
        perror("listen the socket");
        return -1;
    }

    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);

    while(1)
    {
        int fd;
        int nread;
        rset = allset;
        FD_ZERO(readfds);
        result = select(FD_SETSIZE, &rset, NULL, NULL, NULL);
        if(result < 1)
        {
            perror("server 5");
            exit(1);
        }

        // 
        for(fd=0; fd

クライアントテスタ:
#include  
#include  
#include  
#include                                                                     
#include  
#include  
#include 
#include 

#define MAXLINE      4096
#define SERVPORT     7885


int main(int argc, char *argv[]) 
{ 
    int client_sockfd; 
    int len; 
    struct sockaddr_in address;//                                            
    int result; 
    char sendline[MAXLINE],recvline[MAXLINE];

    if(argc != 2)
    {
       printf("usage:tcpcli 
"); return 0; } client_sockfd = socket(AF_INET, SOCK_STREAM, 0);// socket address.sin_family = AF_INET; inet_pton(AF_INET, argv[1], &address.sin_addr); address.sin_port = htons(SERVPORT); len = sizeof(address); result = connect(client_sockfd, (struct sockaddr *)&address, len); while(1) { if(result == -1) { perror("oops: client2"); exit(1); } if(fgets(sendline, MAXLINE, stdin) == NULL) { return -1; } printf("sendline is %s
", sendline); write(client_sockfd, sendline, strlen(sendline)); // recvline memset(recvline, 0, sizeof(recvline)); read(client_sockfd, recvline, strlen(sendline)); printf("char from server = %s
", recvline); } close(client_sockfd); return 0; }