選択機能の役割:
サーバーからのデータの読み取りとキーボードからのデータの読み取りを同時に行うなど、ブロックする必要のあるプログラムの場所が2つある場合(ブロックとクエリを使用しない場合、システムリソースが大量に消費されます)。現在、2つのブロッキングがあります。もちろん、マルチスレッドまたはマルチプロセスの方法を使用して解決できますが、今日は別の方法を紹介します。I/ O多重化(選択、ポーリング、その他のメカニズムなど)、選択して監視できますファイル記述子の変更を監視する必要があります-読み取りまたは書き込みまたは異常。
头文件:
#include <sys/select.h>
函数原型:
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
パラメータ:
1.int maxfdpは整数値です。これは、コレクション内のすべてのファイル記述子の範囲を参照します。つまり、すべてのファイル記述子の最大値に1を加えたものは、間違いではありません。Windowsでは、このパラメーターの値は重要ではなく、誤って設定される可能性があります。
2.fd_set * readfds FD_SET構造は、ポインタへのポインタで、このコレクションは、私たちがいることを、これらのファイル記述子でモニター変化に読み込まれ、ファイル・ディスクリプタを含める必要があります我々は、これらのデータをファイルから読み込むことができるかどうかを懸念している場合は、コレクションに読み取り可能なファイルがある場合、selectは0より大きい値を返します。これは、読み取り可能なファイルがない場合、読み取り可能なファイルがあることを示し、タイムアウトパラメータに従ってタイムアウトするかどうかを決定し、タイムアウトを超えた場合、selectは0を返します。エラーが発生した場合、負の値が返されます。NULL値を入力できます。これは、ファイルの読み取り変更を気にしないことを示します。
3. fd_set * writefdsはfd_set構造体へのポインタです。このセットにはファイル記述子を含める必要があります。これらのファイル記述子の書き込み変更を監視します。つまり、これらのファイルにデータを書き込むことができるかどうかを懸念しますコレクションに書き込み可能なファイルがある場合、selectは0より大きい値を返し、書き込み可能なファイルがあることを示します。書き込み可能なファイルがない場合、タイムアウトはタイムアウトに従って決定されます。エラーが発生すると負の値が返されます。NULL値を渡して、ファイル書き込みの変更を気にしないことを示すことができます。
4.fe_set * errorfdsは、ファイルエラーの例外を監視するために使用される、上記の2つのパラメーターの意図と同じです。
5. struct timeval * timeoutはselectのタイムアウトです。このパラメーターは非常に重要で、3つの状態でselectを実行できます。
最初:仮パラメーターとしてNULLが渡された場合、つまり時間構造が渡されなかった場合、選択はブロックされた状態になります、監視ファイル記述子セットでファイル記述子が変更されるまで待機する必要があります
。2番目:時間値が0秒0ミリ秒に設定されている場合、ファイル記述子が変更されたかどうかに関係なく、純粋な非ブロッキング関数になります。すべてがすぐに実行を続行し、変更がない場合は0を返し、変更がある場合は正の値を返します
。3番目:タイムアウトの値が0より大きい場合、これは待機のタイムアウト期間です。つまり、タイムアウト期間内に選択がブロックされ、タイムアウト期間内にイベントが到着します。戻ります。それ以外の場合は、タイムアウト後も戻り値は上記と同じです。
戻り値:
負の値:選択エラー、
正の値:一部のファイルは読み取りまたは書き込み、またはエラーが発生する可能性があります
。0:タイムアウトを待機します。読み取り、書き込み、または誤ったファイルはありません。
エラーコード:
実行が成功した場合、ステータスが変更されたファイル記述子の数が返されます。0が返された場合は、記述子ステータスが変更される前にタイムアウト期間が経過したことを意味します。エラーが発生した場合は-1が返されます。エラーの原因はerrnoに格納されます。パラメータreadfds、 writefds、exceptfds、およびtimeoutの値は予測不能になります。
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n为负值。
ENOMEM 核心内存不足
機能の説明:
select()は、ファイル記述子の状態が変化するのを待つために使用されます。パラメーターmaxfdpは最大のファイル記述子に1を加えたものを表し、パラメーターreadfds、writefds、exceptingfdsは記述句と呼ばれ、読み取り、書き込み、または例外のステータスを記述子に返すために使用されます。以下のマクロは、これら3つの記述句を処理する方法を提供します。
FD_CLR(inr fd,fd_set* set); 用来清除描述词组set中相关fd的位
FD_ISSET(int fd,fd_set *set); 用来测试描述词组set中相关fd的位是否为真
FD_SET(int fd,fd_set*set); 用来设置描述词组set中相关fd的位
FD_ZERO(fd_set *set); 用来清除描述词组set的全部位
構造の説明:
1)struct fd_setは、ファイル記述子(filedescriptors)、つまりファイルハンドルを格納するセットとして理解できます。これは、通常の意味のファイルと呼ばれるものであり、もちろん、UNIXでのデバイス、パイプライン、FIFOなどです。これはファイルの形式で、すべて含まれているため、ソケットがファイルであり、ソケットハンドルがファイル記述子であることは間違いありません。
fd_setコレクションは、次のようなマクロによって手動で操作できます。
清空集合FD_ZERO(fd_set *);
将一个给定的文件描述符加入集合之中FD_SET(int ,fd_set*);
将一个给定的文件描述符从集合中删除FD_CLR(int,fd_set*);
检查集合中指定的文件描述符是否可以读写FD_ISSET(int ,fd_set* )。一会儿举例说明。
2)struct timevalは、時間の値を表すために誰もが一般的に使用する構造で、2つのメンバーがあり、1つは秒で、もう1つは微妙な数値です。以下に示すように:
truct timeval
{
time_t tv_sec; //seconds 秒
time_t tv_usec; //microseconds 微秒,1000000 微秒 = 1秒
};
//头文件
#include <sys/time.h>
注:
1. select()関数で設定された各ファイル記述子fd_setのパラメーターは、select()の前後に変更を送信しました。
前:対象のファイル記述子のコレクションを示します
後:データのコレクション(タイムアウトで返されない場合)
つまり、最初に監視対象の各I / Oのファイル記述子をfd_setコレクションに設定し、次にselect()を呼び出し、最後にfd_setコレクションには「異常」(読み取り、書き込み、異常を含む)ファイルのみが含まれます。ディスクリプタは、fd_setコレクションを設定し、select()を呼び出し、どのIOにデータがあるかを判別するための上記の手順は、通常、whileループで実装されます。
2. select関数を呼び出す前後にfd_setコレクションによって送信された変更は、カーネルによって行われます。
例1:Linuxで監視キーボードにデータが送られてきますか?
#include <sys/time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int main ()
{
int keyboard;
int ret,i;
char c;
fd_set readfd;
struct timeval timeout;
keyboard = open("/dev/tty",O_RDONLY | O_NONBLOCK);
assert(keyboard>0);
while(1)
{
timeout.tv_sec=1;
timeout.tv_usec=0;
FD_ZERO(&readfd); //结构体清0
FD_SET(keyboard,&readfd); //把键盘文件的句柄加入"读集合"之中
///监控函数
ret=select(keyboard+1,&readfd,NULL,NULL,&timeout); //第一个参数为最大文件句柄+1
if(ret == -1) //错误情况
cout<<"error"<<endl ;
else if(ret) //返回值大于0 有数据到来
if(FD_ISSET(keyboard,&readfd)) //检查集合中键盘文件是否可以读(因为加入"读集合"的可能不止键盘)
{
/* 读出键盘的数据 */
i=read(keyboard,&c,1);
if('\n'==c)
continue;
printf("hehethe input is %c\n",c);
if ('q'==c)
break;
}
else //超时情况
{
cout<<"time out"<<endl;
continue;
}
}
}
例2:Linuxで複数のファイルの監視が読み取り可能か(疑似コード)?
1.
fd_set tRFds; //定义fd_set类型结构体的变量tRFds
FD_ZERO(&tRFds); //结构体先清0
int g_iMaxFd = -1; //定义g_iMaxFd记录 最大句柄+1
2.
比较要监控的各个文件的句柄,取出最大值再加1赋给g_iMaxFd
if(Fd1 > Fd2)
{
g_iMaxFd = Fd1+1;
}
else
{
g_iMaxFd = Fd2+1;
}
3.
FD_SET(Fd1, &tRFds); //把Fd1、Fd2加入"读集合"之中
FD_SET(Fd2, &tRFds); //Fd1和Fd2为两个不同的文件句柄
...
4.
iRet = select(g_iMaxFd, &tRFds, NULL, NULL, NULL);
if (iRet > 0) //返回正数说明有数据可读了
{
if (FD_ISSET(Fd1, &tRFds)) //是文件1可读
{
Fd1_read(...);
}
else if(FD_ISSET(Fd2, &tRFds)) //是文件2可读
{
Fd2_read(...);
}
...
}
この記事の主な参考資料:https : //blog.csdn.net/mayue_web/article/details/89021273