多重化されたI/Oの同期をとる。すなわち、複数のファイル・ディスクリプタ(オープンされたファイルまたはデバイス)を監視し、それらの変化を待つUNIXのselectシステムコール。 機能の詳細は端末エミュレータ上でman selectを実行しman ページを参照せよ。
selectシステムコールを使って複数の入力を監視するサンプル1server_sel.cを示す。
/******************************************************************/ /*** server_sel.c ***/ /*** 入力: クライアントからの接続要求 ***/ /*** (7個までのクライアントの接続に対応) ***/ /*** 出力: 約1秒毎に、接続中の全クライアントに対して、 ***/ /*** カウントダウン中のカウンタの値をメッセージとして送信 ***/ /******************************************************************/ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/un.h> #include <sys/unistd.h> #define MAX_SOCKS 9 int main() { int s; int ss; int addrlength; char write_buf[1024]; int k; /************************************************************/ /* ソケットを格納する配列 */ /* socks[0] には listening ソケットを格納 */ /* socks[1...(last_socks-1)] には accept したソケットを格納 */ /************************************************************/ int socks[MAX_SOCKS]; int last_socks; /****************************************/ /* 入力のファイル・ディスクリプタの集合 */ /****************************************/ fd_set rfds; /***********************************************************/ /* select() から返ってくるまでの時間の上限を設定する構造体 */ /***********************************************************/ /* struct timeval { */ /* long tv_sec; /* 秒 */ /* long tv_usec; /* マイクロ秒 */ /* }; */ /***********************************************************/ struct timeval tv; /* カウントダウンのためのカウンタ */ int count; /* 時間を計るためのタイマー */ int timer; /***************************************************************/ /* ソケットアドレス UNIX */ /***************************************************************/ /* struct sockaddr_un { */ /* sa_family_t sun_family; /* AF_UNIX */ /* char sun_path[UNIX_PATH_MAX]; /* pathname */ /* }; */ /***************************************************************/ struct sockaddr_un addr; /****************************************/ /* ソケット、通信のための端点の作成 */ /* PF_UNIX: UNIX ローカル通信 */ /* SOCK_STREAM: 順序性と信頼性があり、 */ /* 双方向の、接続された */ /* バ イ ト・ ス ト リーム */ /****************************************/ s = socket(PF_UNIX, SOCK_STREAM, 0); if (s == -1) { printf("Can not create socket.\n"); exit(1); } /******************************/ /* アドレスの設定 */ /* AF_UNIX: UNIX ローカル通信 */ /* 名前: mysocket */ /******************************/ addr.sun_family = AF_UNIX; strcpy(addr.sun_path, "mysocket"); /************************************/ /* ソケットに名前、アドレスを与える */ /************************************/ addrlength = sizeof(addr); if (bind(s, (struct sockaddr *)&addr, addrlength) == -1) { printf("Can not assign the address to a socket.\n"); exit(1); } /****************************/ /* ソケット上の接続を待つ */ /* 接続を待機させる最大数 2 */ /****************************/ if (listen(s, 2) == -1) { printf("Can not listen for connections.\n"); exit(1); } printf("listen...\n"); /****************************************/ /* listening ソケットを socks[0] に格納 */ /****************************************/ last_socks = 0; socks[last_socks] = s; last_socks++; timer = 0; /* タイマーの初期化 */ count = 20; /* カウンタの初期化 */ while (1) { /******************************************************/ /* 入力のファイル・ディスクリプタの集合 rfds を clear */ /******************************************************/ FD_ZERO(&rfds); /*********************************************/ /* 入力のディスクリプタの集合 rfds に */ /* listening ソケット socks[0] と */ /* 接続中の socks[1...(last_socks-1)] を追加 */ /*********************************************/ for (k = 0; k < last_socks; k++) { FD_SET(socks[k], &rfds); } /******************************************************/ /* select から 100000 マイクロ秒で返ってくるように指定 */ /******************************************************/ tv.tv_sec = 0; tv.tv_usec = 100000; /***********************************************************/ /* select システムコール */ /* rfds にリストされた入力のファイル・ディスクリプタを監視 */ /* タイムアウト時間は 100 ミリ秒 */ /***********************************************************/ select(FD_SETSIZE, &rfds, NULL, NULL, &tv); printf("."); /****************************************************************/ /* listening ソケット socks[0] に接続があったかどうかのチェック */ /****************************************************************/ if (FD_ISSET(socks[0], &rfds)) { /* 接続あり */ /* socks[] があふれないかどうかのチェック */ if (last_socks < MAX_SOCKS) { /* あふれない */ /****************************/ /* ソケット上の接続を受ける */ /* 待ちなし */ /****************************/ ss = accept(socks[0], (struct sockaddr *)&addr, &addrlength); printf("\nAccepted... last_socks=%d\n", last_socks); /****************************************/ /* accept したソケットを socks[] に追加 */ /****************************************/ socks[last_socks] = ss; last_socks++; } else { /* socks[] があふれる場合 */ printf("Too many socks. last_socks=%d, MAX_SOCKS=%d\n", last_socks, MAX_SOCKS); break; } } /******************************/ /* 約1秒たったかどうかの確認 */ /******************************/ if (timer == 10) { /* 約1秒たった(100ミリ秒×10)*/ timer = 0; /********************************************************/ /* 接続中の全クライアント socks[1...(last_socks-1)] に */ /* カウントダウン中のカウンタの値をメッセージとして送信 */ /********************************************************/ for (k = 1; k < last_socks; k++) { /****************/ /* write で送信 */ /****************/ sprintf(write_buf, "%d\n", count); printf("write_buf=%s\n", write_buf); ss = socks[k]; write(ss, write_buf, strlen(write_buf)+1); } /*********************************************/ /**** カウンタが0になったかどうかのチェック */ /*********************************************/ if (count == 0) { /* なった */ count = 20; break; } else { count--; } } else { /* まだ1秒たたない */ timer++; } } /**********************/ /* ソケットのクローズ */ /**********************/ shutdown(s, 2); close(s); unlink("mysocket"); } |
selectシステムコールを使って複数の入力を監視するサンプル2client_sel.cを示す。
/************************************/ /*** client_sel.c ***/ /*** 入力: サーバからのメッセージ ***/ /*** 出力: サーバへの接続要求 ***/ /************************************/ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> int main() { int s; int addrlength; char read_buf[1024]; /****************************************/ /* 入力のファイル・ディスクリプタの集合 */ /****************************************/ fd_set rfds; /***********************************************************/ /* select() から返ってくるまでの時間の上限を設定する構造体 */ /***********************************************************/ /* struct timeval { */ /* long tv_sec; /* 秒 */ /* long tv_usec; /* マイクロ秒 */ /* }; */ /***********************************************************/ struct timeval tv; /***************************************************************/ /* ソケットアドレス UNIX */ /***************************************************************/ /* struct sockaddr_un { */ /* sa_family_t sun_family; /* AF_UNIX */ /* char sun_path[UNIX_PATH_MAX]; /* pathname */ /* }; */ /***************************************************************/ struct sockaddr_un addr; /****************************************/ /* ソケット、通信のための端点の作成 */ /* PF_UNIX: UNIX ローカル通信 */ /* SOCK_STREAM: 順序性と信頼性があり、 */ /* 双方向の、接続された */ /* バ イ ト・ ス ト リーム */ /****************************************/ s = socket(PF_UNIX, SOCK_STREAM, 0); if (s == -1) { printf("Can not create socket.\n"); exit(1); } /******************************/ /* アドレスの設定 */ /* AF_UNIX: UNIX ローカル通信 */ /* 名前: mysocket */ /******************************/ addr.sun_family = AF_UNIX; strcpy(addr.sun_path, "mysocket"); /**********************/ /* ソケットに接続する */ /**********************/ addrlength = sizeof(addr); if (connect(s, (struct sockaddr *)&addr, addrlength) == -1) { printf("Can not initiate a connection.\n"); exit(1); } printf("connected.\n"); while (1) { /******************************************************/ /* 入力のファイル・ディスクリプタの集合 rfds を clear */ /******************************************************/ FD_ZERO(&rfds); /**************************************/ /* 入力のディスクリプタの集合 rfds に */ /* 接続中の s を追加 */ /**************************************/ FD_SET(s, &rfds); /******************************************************/ /* select から 100000 マイクロ秒で返ってくるように指定 */ /******************************************************/ tv.tv_sec = 0; tv.tv_usec = 100000; /***********************************************************/ /* select システムコール */ /* rfds にリストされた入力のファイル・ディスクリプタを監視 */ /* タイムアウト時間は 100 ミリ秒 */ /***********************************************************/ select(FD_SETSIZE, &rfds, NULL, NULL, &tv); /**********************************************/ /* s が待ちなしで読み込めるかどうかのチェック */ /**********************************************/ if (FD_ISSET(s, &rfds)) { /* 待ちなしで読める */ /****************************/ /* s からのデータの読み込み */ /****************************/ read(s, read_buf, sizeof(read_buf)); printf("read_buf[]=%s\n", read_buf); if ((read_buf[0] == '0') && (read_buf[1] == '\n') && (read_buf[2] == '\0')) { printf("finished."); break; } } } /**********************/ /* ソケットのクローズ */ /**********************/ shutdown(s, 2); close(s); } |