epoll についての深い理解

概要

ネットワーク プログラミングでは、多数の同時接続を効率的に処理することが重要な問題です。Linux が提供する epoll メカニズムは、この問題を解決する重要なツールとなっています。epoll は I/O イベント通知メカニズムであり、epoll_create、epoll_ctl、および epoll_wait という 3 つの主要な関数を通じて高性能のイベント駆動型同時プログラミングを実現します。これら 3 つの機能とその使用方法を詳しく見てみましょう。

1. epoll_create - epoll インスタンスを作成します

int epoll_create(int size);

size: 作成された赤黒ツリーのリスナー ノードの数。(カーネル参照のみ。)
戻り値: fd は、新しく作成された赤黒ツリーのルート ノードを指します。
-1: エラーを表します

2. epoll_ctl - epoll インスタンスのイベントを制御します

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epfd: epoll_create 関数の戻り値。epfd
op: 監視されている赤と黒の番号に対して実行される操作。
EPOLL_CTL_ADD 赤黒ツリーをリッスンする fd を追加します
。 EPOLL_CTL_MOD 赤黒ツリー上のリッスン イベントをリッスンするように fd を変更します。
EPOLL_CTL_DEL 監視赤黒ツリーから fd を削除(監視解除)
fd: 監視対象の fd
イベント: 本質 struct epoll_event 構造体ポインタ
戻り値: 成功 0; 失敗: -1 errno

構造の紹介

struct epoll_event {
    
    
		__uint32_t events; /* Epoll events */
		epoll_data_t data; /* User data variable */
	};
	typedef union epoll_data {
    
    
		void *ptr;
		int fd;
		uint32_t u32;
		uint64_t u64;
	} epoll_data_t;

イベント値:

EPOLLIN: 対応するファイル記述子が読み取り可能であることを示します (ピア SOCKET の通常のクローズを含む)
EPOLLOUT: 対応するファイル記述子が書き込み可能であることを示します
EPOLLERR: 対応するファイル記述子にエラーがあることを示します
(重要ではありません)

データ: 組合 (コミュニティ):

int fd; fd void *listen イベントに対応するptr
; コールバック関数
uint32_t u32;
uint64_t u64;

3. epoll_wait - イベントが発生するのを待ちます

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

epoll_wait 関数は、イベントの発生を待機するために使用され、イベントが発生すると、準備ができたファイル記述子と対応するイベント タイプを返します。パラメータには次のものが含まれます。

epfd: epoll_create 関数の戻り値。epfd

events: 送信パラメータ、[配列]、監視条件を満たす fd 構造。

maxevents: 上記の配列内の要素の総数。例:struct epoll_event evnets[1024]->1024

timeout:
-1: ブロックする
0: ブロックしない
0 より大きい: タイムアウト (ミリ秒)
戻り値:
0 より大きい: リスナーの総数。ループキャップとしても使用可能。
0: listen イベントを満たす fd がありません
-1: 失敗しました。エラーノ

ここに画像の説明を挿入

疑似コード

コードの実装については、次を参照してください:マルチチャネル IO 転送のアイデアを実現するためのリンクepoll:

lfd = socket();			监听连接事件lfd
bind();
listen();

int epfd = epoll_create(1024);				epfd, 监听红黑树的树根。

struct epoll_event tep, ep[1024];			tep, 用来设置单个fd属性, ep 是 epoll_wait() 传出的满足监听事件的数组。

tep.events = EPOLLIN;					初始化  lfd的监听属性。
tep.data.fd = lfd

epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &tep);		将 lfd 添加到监听红黑树上。

while (1) {
    
    

	ret = epoll_wait(epfd, ep,1024-1);			实施监听

	for (i = 0; i < ret; i++) {
    
    
		
		if (ep[i].data.fd == lfd) {
    
    				// lfd 满足读事件,有新的客户端发起连接请求

			cfd = Accept();

			tep.events = EPOLLIN;				初始化  cfd的监听属性。
			tep.data.fd = cfd;

			epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &tep);

		} else {
    
    						cfd 们 满足读事件, 有客户端写数据来。

			n = read(ep[i].data.fd, buf, sizeof(buf));

			if ( n == 0) {
    
    

				close(ep[i].data.fd);

				epoll_ctl(epfd, EPOLL_CTL_DEL, ep[i].data.fd , NULL);	// 将关闭的cfd,从监听树上摘下。

			} else if (n > 0{
    
    --write(ep[i].data.fd, buf, n);
			}
		}
	}

要約する

3 つの主要な関数 epoll_create、epoll_ctl、および epoll_wait を使用すると、Linux の epoll メカニズムを最大限に活用して、効率的なイベント駆動型の同時プログラミングを実現できます。まず、epoll インスタンスを作成することで、複数のファイル記述子を監視できます。次に、epoll_ctl 関数を使用して、監視する必要があるイベントを追加、変更、削除します。最後に、イベントが発生するのを待ち、epoll_wait 関数を呼び出して準備ができたファイル記述子を処理します。

これらの機能を合理的に使用すると、多数の同時接続を効果的に管理し、システムのパフォーマンスと応答性を向上させることができます。もちろん、実際のアプリケーションでは、より安定した効率的なネットワーク アプリケーションを実現するために、他のネットワーク プログラミングの知識とスキルを組み合わせる必要もあります。

おすすめ

転載: blog.csdn.net/qq_46017342/article/details/132308231