debugfsのマウントとprintkの出力レベル変更
# mount -t debugfs none /sys/kernel/debug # echo 8 >/proc/sys/kernel/printk
ソースファイルのコメントをman形式で出力する方法
linux/scripts/kernel-doc drivers/i2c/i2c-core.c |nroff -man
■
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; } } } } }
■
P.157より。select()を使用することにより、複数のディスクリプタに対してそれらの準備が出来るまで待つことが出来る。また、ソケットプログラミングにおいて相手側のコネクションがクロースするや否や、それを通知することが出来る。また、shutdown()を使用することにより、TCPをハーフクローズさせている。これにより、送信は不可でありながら受信は可能となる。
#include "unp.h" /* * echoクライアントのメイン関数。 * 1. ファイルポインタ(普通は標準入力)から入力を受け取り、それをソケットに書き込む。 * 2. 書き込みに応じた応答をソケットから受け取り、それを標準出力に書き出す。 */ void str_cli(FILE *fp, int socket_fd) { int stdin_eof_flg = 0; /* このフラグがゼロである限りループ内で標準入力 * の読み出し可能性をselect()で検査し続ける */ int fd; int max_fd_plus1; fd_set rset; char sendline[MAXLINE]; char recvline[MAXLINE]; FD_ZERO(&1rset); /* ディスクリプタ集合の初期化 */ for ( ; ; ) { /* フラグがゼロならば標準入力を検査する。そうでなければ入力は終了して * いるので検査しない。 */ if (stdin_eof_flg == 0) { fd = fileno(fp); /* fileno()は、ファイルポインタのディスクリプタを返す */ FD_SET(fd, &rset); /* fdに対応するビットをディスクリプタ集合にセットする */ } /* socket_fdに対応するビットをディスクリプタ集合にセットする */ FD_SET(socket_fd, &rset); /* 2つのディスクリプタの最大値の算出。これは重要 */ max_fd_plus1 = max(fileno(fp), socket_fd) + 1; /* いよいよselectの実行。どちらかのディスクリプタが読み出し可能となる * までブロックする。尚、ディスクリプタ集合rsetは"値-結果引数"であるの * で、関数から戻った時には用意できていないディスクリプタのビットはク * リアされている。よってselect()をcallする度に監視対象ディスクリプタ * をセットし直す必要が有ることに注意すること。 * * ・書き込みの監視:しない * ・例外の監視 :しない * ・タイムアウト :なし */ Select(max_fd_plus1, &rset, NULL, NULL, NULL); if (FD_ISSET(socket_fd, &rset)) { /* ソケットが読み出し可能となった */ if (Readline(socket_fd, recvline, MAXLINE) == 0) { if (stdin_eof_flg == 1) { /* 標準入力からの入力が完了状態であり、かつ、ソケット上 * でEOF状態を検出した(つまりサーバがFINを発行した)ので、 * 正常終了とする */ goto end; } else { err_quit("str_cli: server terminated prematurely"); } } Fputs(recvline, stdout); } if (FD_ISSET(fileno(fp), &rset)) { /* 標準入力が読み出し可能となった */ if (Fgets(sendline, MAXLINE, fp) == NULL) { stdin_eof_flg = 1; /* もはやソケットへの書き込みは行わない為、shutdown()を送信 * 禁止でcallする。これにより対面のTCPエンドポイントへFINが * 送られる。これ以後、ソケットへの送信は行われないが、受信 * は継続して行われる。これは、クライアントの入力が終了して * もサーバへの、或いはサーバからのパイプ中にデータがある可 * 能性があることに対する対処である。 */ Shutdown(socket_fd, SHUT_WR); /* 標準入力をディスクリプタ集合から削除する */ FD_CLR(fileno(fp), &rset); continue; } Writen(socket_fd, sendline, strlen(sendline)); } } end: return; }
■
リチャードスティーブンス氏の著作より、簡単なTCP daytimeクライアントとサーバのコード。
- daytimetcpcli.c
#include "unp.h" int main(int argc, char **argv) { int socket_fd; int read_bytes; char recvline[MAXLINE + 1]; struct sockaddr_in servaddr; /* インターネットソケットアドレス構造体 */ if (argc != 2) err_quit("usage: a.out"); /* TCPソケットの作成。インターネット(AF_INET)のストリーム(SOCK_STREAM) * ソケット、つまりTCPソケットを作成する。 */ if ( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) err_sys("socket error"); /* サーバのIPアドレスとポートの指定 */ memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; /* アドレスファミリの指定 */ servaddr.sin_port = htons(13); /* ポート番号をホストバイトオーダーから * ネットワークバイトオーダーに変換(host * to network short)する。13はdaytime se * rverのウェルノウンポート。 */ /* 引数で指定したIPアドレスを変換(presentation to numeric)して構造体に格納する */ if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) err_quit("inet_pton error for %s", argv[1]); /* ソケットアドレス構造体で指定したサーバとのTCPコネクションを確立する。 * &serveraddrをキャストしている理由についてはP.60を参照のこと。 */ if (connect(socket_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) err_sys("connect error"); /* サーバからの応答をread()で読み取り、標準出力に書き出す。TCPはレコード境 * 界を持たないバイトストリームプロトコルであるため、使用には注意が必要。 */ while ( (read_bytes = read(socket_fd, recvline, MAXLINE)) > 0) { /* ゼロは他方のエンドのコネクションクローズ。負の数はエラー。 */ recvline[read_bytes] = '\0'; /* null terminate */ if (fputs(recvline, stdout) == EOF) err_sys("fputs error"); } if (read_bytes < 0) err_sys("read error"); /* TCPソケットもファイルディスクリプタなのでexit()によりクローズされる。 */ exit(0); }
こちらはサーバ。先頭が大文字の関数は、エラー処理を内包したラッパ関数であることを意味する。
- daytimetcpsrv.c
#include "unp.h" #includeint main(int argc, char **argv) { int listen_fd; int connected_fd; char buff[MAXLINE]; time_t ticks; struct sockaddr_in servaddr; listen_fd = Socket(AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(13); /* daytime server */ /* 接続を待つIPアドレスの指定。 INADDR_ANYは、どのインターフェースに宛てた * クライアントからのコネクションでも受け付ける事を意味する。 * INADDR_ANY = (in_addr_t) 0x00000000 */ servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ソケットにローカルアドレスservaddrを割り当てる。伝統的にこの処理は「ソケ * ットに名前をつける」と呼ばれる。 */ Bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)); /* listen()を呼び出し、ソケットをリスニングソケットに変換する。これにより、 * カーネルがクライアントからのコネクションを受け付けるようになる。 * socket, bind, listenという3段階の処理は、全てのTCPサーバがリスニングデ * ィスクリプタを用意する為の通常の手段である。 */ Listen(listen_fd, LISTENQ); /* クライアントからのコネクションを受け付け、応答を返す。尚、このサーバは同 * 時に1クライアントしか扱えない事に留意すること。 */ for ( ; ; ) { /* accept()は、接続要求キューから要求を取り出し、接続済みソケットを作 * 成し、そのソケットのディスクリプタを返す。元のソケットは影響を受け * ない。尚、ここではクライアントプロセスのプロトコルアドレスの取得は * 行わない(NULL, NULL) */ connected_fd = Accept(listen_fd, (struct sockaddr *) NULL, NULL); ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); /* 接続済みディスクリプタに値を書き込む。これによりクライアントへデー * タが送信される。 */ Write(connected_fd, buff, strlen(buff)); /* クライアントとのコネクションをクローズする。これによりTCPコネクショ * ンの通常終了シーケンス(双方向のFIN等)が起動される。 */ Close(connected_fd); } }
サーバ側でクライアントのIPアドレスとポートを出力するには、daytimetcpsrv.cを以下のように変更する。
--- intro/daytimetcpsrv.c.org 1997-05-09 06:00:59.000000000 +0900 +++ intro/daytimetcpsrv.c 1997-06-06 20:40:57.000000000 +0900 @@ -5,7 +5,8 @@ int main(int argc, char **argv) { int listenfd, connfd; - struct sockaddr_in servaddr; + socklen_t len; + struct sockaddr_in servaddr, cliaddr; char buff[MAXLINE]; time_t ticks; @@ -21,7 +22,11 @@ main(int argc, char **argv) Listen(listenfd, LISTENQ); for ( ; ; ) { - connfd = Accept(listenfd, (struct sockaddr *) NULL, NULL); + len = sizeof(cliaddr); + connfd = Accept(listenfd, (struct sockaddr *) &cliaddr, &len); + printf("connection from %s, port %d\n", + Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)), + ntohs(cliaddr.sin_port)); ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
■
[Solaris] Apache2サービスの起動
SMFサービス詳細情報の確認
/ # svcs -a | grep apache legacy_run 9月_16 lrc:/etc/rc3_d/S50apache ←Apacheはレガシーサービス disabled 9月_16 svc:/network/http:apache2 ←Apache2はSMFサービス / # svcs -l apache2 ←サービスの詳細 fmri svc:/network/http:apache2 name Apache 2 HTTP server 有効 false 状態 disabled next_state none state_time 2008年09月16日 16時47分41秒 リスタータ svc:/system/svc/restarter:default dependency require_all/error svc:/network/loopback:default (online) dependency optional_all/error svc:/network/physical:default (online) / # svcprop apache2 | grep exec ←起動スクリプトの確認 start/exec astring /lib/svc/method/http-apache2\ start stop/exec astring /lib/svc/method/http-apache2\ stop refresh/exec astring /lib/svc/method/http-apache2\ refresh
Apache2マニフェストファイル
/var/svc/manifest/network/http-apache2.xml
Apache2サービスの起動
/ # svcadm -v enable apache2 svc:/network/http:apache2 が有効になりました。 / # svcs -a | grep apache2 online 18:07:09 svc:/network/http:apache2 / # cat /var/run/apache2/httpd.pid 13130 / # ptree | grep http 13160 /usr/bin/grep http 13130 /usr/apache2/bin/httpd -k start 13131 /usr/apache2/bin/httpd -k start 13132 /usr/apache2/bin/httpd -k start 13133 /usr/apache2/bin/httpd -k start 13134 /usr/apache2/bin/httpd -k start 13135 /usr/apache2/bin/httpd -k start 13154 /usr/apache2/bin/httpd -k start / # netstat -an -f inet -P tcp | grep \.80 *.80 *.* 0 0 49152 0 LISTEN
■
SMF(svc)
Service Management Facility。共通マネージメントシステム。従来のSolarisでは、各サービスはinit.d以下のrcスクリプトから起動されていた。それに変わるもの。
Solarisコンテナ
Solaris10の新機能。一台の物理ハードウェア上に複数の独立した実行環境(コンテナ)を動作させる技術。Solarisコンテナは、サーバの仮想化を行うSolarisゾーンと、ゾーンに対してリソース配分を行うSolarisリソース管理の2つの機能で構成される。
DTrace
Solaris10から。主にシステム障害やパフォーマンス低下を特定する為のツール。カーネル内部に埋め込まれた観測ポイント(プローブ)の動的ON/OFFが可能。