■
poll()を使用したechoサーバの例
#include "unp.h" #define OPEN_MAX 16 int main(int argc, char **argv) { int i; int max_fd_index = 0; /* 利用可能なディスクリプタの最大の添字 */ int listen_fd; int connected_fd; int socket_fd; int num_of_ready_fd; ssize_t n; char line[MAXLINE]; socklen_t clilen; struct pollfd client[OPEN_MAX]; struct sockaddr_in client_addr; struct sockaddr_in server_addr; /* サーバ起動の常套手順 */ listen_fd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(SERV_PORT); Bind(listen_fd, (SA *) &server_addr, sizeof(server_addr)); Listen(listen_fd, LISTENQ); client[0].fd = listen_fd; /* 配列の最初のディスクリプタはリスニングソ * ケットである */ client[0].events = POLLIN; /* リクエストイベントの設定。ここでは、読み * 出し可能となる、つまり新規コネクションが * 受け付け可能な状態になったら、pollから通 * 知されるようにする。 */ /* 最初の要素以外は利用可能な状態で初期化する */ for (i = 1; i < OPEN_MAX; i++) { client[i].fd = -1; } for ( ; ; ) { /* タイムアウト無しでディスクリプタ集合におけるイベントを待つ */ num_of_ready_fd = Poll(client, max_fd_index+1, INFTIM); if (client[0].revents & POLLIN) { /* リスニングソケットのリターンイベントが"読み出し可能"であった場 * 合、つまり、新規クライアントコネクションが発生した場合 */ clilen = sizeof(client_addr); connected_fd = Accept(listen_fd, (SA *) &client_addr, &clilen); /* エントリに余裕があれば、新規コネクションのディスクリプタをディ * スクリプタ集合に保存する */ for (i = 1; i < OPEN_MAX; i++) { if (client[i].fd < 0) { client[i].fd = connected_fd; break; } } if (i == OPEN_MAX) { err_quit("too many clients"); } /* 新規コネクションを読み出し待ちでポーリングするように設定する */ client[i].events = POLLIN; /* 必要なら、添字を更新する */ if (i > max_fd_index) { max_fd_index = i; } num_of_ready_fd--; if (num_of_ready_fd <= 0) { /* 読み出し可能なディスクリプタが無いので以下の処理はスキップ */ continue; } } /* 読み出し可能なディスクリプタが存在すればここに到達する */ for (i = 1; i <= max_fd_index; i++) { /* ディスクリプタが設定されている要素を検索する */ if ( (socket_fd = client[i].fd) < 0) { continue; } if (client[i].revents & (POLLIN | POLLERR)) { /* POLLERRは状況に応じて自動 * 的にセットされる */ if ( (n = readline(socket_fd, line, MAXLINE)) < 0) { /* エラー処理 */ if (errno == ECONNRESET) { /* connection reset by client */ Close(socket_fd); client[i].fd = -1; } else err_sys("readline error"); } else if (n == 0) { /* コネクションがクローズされた。Linux 2.6.17 以降ではPOLLRDHUPが * 使える。 */ Close(socket_fd); client[i].fd = -1; } else { /* 通常処理 */ Writen(socket_fd, line, n); } num_of_ready_fd--; if (num_of_ready_fd <= 0) { /* 読み出し可能なディスクリプタがこれ以上無い */ break; } } } } }