epoll_create, epoll_ctlとepoll_wait解説
7157 ワード
NAME
epoll - I/O event notification facility
SYNOPSIS
#include
DEscrīptION
epoll is a variant of poll(2) that can be used either as Edge or Level
Triggered interface and scales well to large numbers of watched fds.
Three system calls are provided to set up and control an epoll set:
epoll_create(2), epoll_ctl(2), epoll_wait(2).
An epoll set is connected to a file descrīptor created by
epoll_create(2). Interest for certain file descrīptors is then
registered via
epoll_ctl(2). Finally, the actual wait is started by epoll_wait(2).
実は、すべての申明はすべて余計で、私の今の理解を守って、EPOLLモデルは1つの構造しかないようで、だから大家は私の下のコードを参考にすれば、EPOLLに対してある程度理解することができて、コードの申明はすべてすでに注釈の中で:
while (TRUE)
{
int nfds = epoll_wait (m_epoll_fd, m_events, MAX_EVENTS, EPOLL_TIME_OUT);// EPOLL , , , EPOLL 。
if (nfds <= 0)
continue;
m_bOnTimeChecking = FALSE;
G_CurTime = time(NULL);
for (int i=0; i
実はEPOLLの精華、私の今の理解を守って、つまり上述のいくつかの短いコード、見たところ時代は本当に合わないで、以前どのように多くのユーザーの接続のテーマを引き継いで、今このように楽に解決されて、本当に感慨を禁じ得ません.
今日一日のepollをして、1つの高い同時の****の代理法度をしたいです.最初は本当に憂鬱で、ずっと通じなくて、ネット上にもepollを紹介する文章がいくつかあります.しかし、すべて深くなく、いくつかの重視するところを疎かにしていません.そのため多くの回り道を歩いて、今自分のいくつかをマスターに共有して、回り道を少なくします.
epollで使用されるすべての関数はヘッダファイルsys/epollです.hの中で声明して、どこが聞き慣れていないかあるいは関数が忘れて見に行くことができます.
epollと比較すると、最大の違いは:
1 epollが戻ってきたとき、どのsokcet fdがトランザクションを生成したのか、もう一つのペアを比べる必要はありません.これで効力が向上した.
2のFD_SETSIZEには限界があり,epollには限界がないのは体系資料のみに関係している.
1、epoll_create関数
関数宣言:int epoll_create(int size)
この
関数はepoll専用のファイル記述子を生成します.カーネルで申請して、あなたが関心を持っているsocketを保存するために使用されています.
fdに何かトランザクションが発生したかどうか、および発生したかどうか.sizeはあなたがこのepoll fdに関心を持つ最大のsocketです.
fd数.君次第だ.あなたが空間さえあれば.上が合わないのが見えます.
2、epoll_ctl関数
関数宣言:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
この関数は、epollファイル記述子上のトランザクションを把握するために使用され、トランザクションを登録したり、トランザクションをバッチしたり、トランザクションを削除したりすることができます.
パラメータ:
使用するデータレイアウト
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
は次のとおりです.struct epoll_event ev;
//トリガを処理するトランザクションに関連するファイル記述子の設定
ev.data.fd=listenfd;
//処理する設定
トリガーされたトランザクション・タイプ
ev.events=EPOLLIN|EPOLLET;
//epollトランザクションの登録
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
よく使用されるトランザクションのタイプ:
EPOLLIN:対応するファイル記述子を黙示して読むことができる;EPOLLOUT:対応するファイル記述子を暗記して書くことができます.EPOLLPRI:デフォルト対応のファイル記述子緊急のデータ読み取り可能なEPOLLERR:デフォルト対応のファイル記述子にエラーが発生する;EPOLLHOP:対応するファイル記述子が切断されたことを黙示する.EPOLLET:対応するファイル記述子にトランザクションが生成されていることを黙示します.
3、epoll_wait関数
関数宣言:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
この関数は、I/Oトランザクションの生成をポーリングするために使用されます.
パラメータ:
epfd:epoll_よりcreateが生成したepoll専用のファイル記述子;
epoll_event:罰トランザクションを代行処理するための配列.
maxevents:罰則を処理できるトランザクションの数.
timeout:I/Oトランザクションを待機するタイムアウト価格(単位もよくわかりません);1は梗塞に相当し、0は非梗塞に相当する.普通は-1でいいです
return:トリガーされたトランザクションの数を返します.
使用法は次のとおりです.
/*build the epoll enent for recall */
struct epoll_event ev_read[20];
int nfds = 0; //return the events count
nfds=epoll_wait(epoll_fd,ev_read,20, -1);
for(i=0; i
{
if(ev_read[i].data.fd == sock)// the listener port hava data
......
epoll_waitが動く理由は
epfdに登録されたsocket fdのトランザクションの生成を待機し、生成されると生成されたsokct fdとトランザクションタイプをevents配列に格納する.epfdに登録されているsocket fdのトランザクションタイプを空にします.
だからもし次の輪廻にあなたがまだこのsocket fdに関心を持っているならば、epoll_を使う必要がありますctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)では最初からsocketを設定します
fdのトランザクションタイプ.このときEPOLL_は使いませんCTL_ADDは、socket fdが空になっていないため、トランザクションタイプが空になっています.この一歩が一番だ.
私は最初はこれを加えなかったので,午前中むだにやった.
4个のepollはすべての问题を解决することができなくて、珍しいのはあなたのすべての操作がすべて努力して时间がかかる时、epollはシリアル処理が触発したためです.
より大きな効率を発揮するために、ツリースレッドプールを構築する必要があります.
//
manではepollの使い方が示されており、example法度は以下の通りである.
for(;;) {
nfds = epoll_wait(kdpfd, events, maxevents, -1);
for(n = 0; n < nfds; ++n) {
if(events[n].data.fd == listener) {
client = accept(listener, (struct sockaddr *) &local,
&addrlen);
if(client < 0){
perror("accept");
continue;
}
setnonblocking(client);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = client;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
fprintf(stderr, "epoll set ion error: fd=%d
",
client);
return -1;
}
}
else
do_use_fd(events[n].data.fd);
}
}
このときETモードが適用される.すなわち、エッジトリガは、レベルトリガと同様に、epollにおけるエッジトリガは、新着データのみを通知することを意味し、カーネルバッファにおいて旧データであれば通知しないのでdo_use_fd関数では、カーネルバッファ内のデータを読み切るために、次のようなループを適用する必要があります.
while (1) {
len = recv(*******);
if (len == -1) {
if(errno == EAGAIN)
break;
perror("recv");
break;
}
do something with the recved data........
}
上の例ではlisten socket fdがトリガをどのように処理するかは明記されていませんが、acceptを傍受するために2つのスレッドが適用される場合があります.もう1つはepoll_を傍受するために使用されます.wait,このように適用すればlisten socket fdはデフォルトの梗塞体式フォーマットを適用すればよいが,epoll_waitとacceptはスレッドにあり、すなわち、すべてepoll_によってwaitが傍受する場合、
Listen socket fdも非梗塞に設定されているため、acceptにもwhileパッケージ(上のrecvに類似)を適用すべきである.なぜなら、epoll_waitが戻った時は接続が来たと言っただけだ
いくつかの接続があるとは言わず、ETモードでepoll_waitは前回の接続がまだ読んでいないので戻ることはありません.このような光景は確かに存在します.私はこの問題のために1日以上かかりました.
ここでは、呼び出しのたびにacceptがカーネル内の接続済みキューのヘッダから接続を読み出すことを明らかにする必要があります.なぜなら、同時接続の場合、複数の接続が「同時」になる可能性があるからです.
達、そしてepoll_waitは一度だけ戻ってきました.
唯一面倒なのはepollには2つのワークスタイルフォーマットがあります:LTとET.
LT(level triggered)はデフォルトのワークスタイルフォーマットであり、blockとno-blockを同時にサポートします.
socket.この方法では、カーネルはファイル記述子が伏線しているかどうかを教えてくれ、この伏線のfdをIO操作することができます.何も操作しないとカーネルは知らせ続けます
したがって、このモードのプログラミングが失敗する可能性は少し小さい.従来の/pollはこのモデルの代表である.
ET(edge-triggered)は高速作業体式フォーマットであり、no-blockのみをサポートする
socket.このモードでは、記述子が伏線から伏線に変わったことがない場合、カーネルはプロセスepollを介して教えてくれます.ファイル記述子が待ち伏せしていることを知っていて、そのファイルについて説明しないと仮定します.
文字は、いくつかの操作を行ってそのファイル記述子が伏線状態にならなくなるまで、より多くの伏線通知を送信します(たとえば、送信、引き継ぎ、引き継ぎの要求、または引き継ぎのデータが必然量より少ない場合にEWOULDBLOCKエラーが発生します).ただし、このfdがIO操作としてエラーに合わない場合は(再び非待ち伏せになる)、カーネルはより多くの通知を送信しません(only
once)ですが、TCPトークでは、ETモードの高速化効果は、より多くのbenchmark確認が必要です.