第 1 部ソケットプログラミング 情報科学科 峰野博史 1
警告は全て除去しましょう gcc Wall ansi O pedantic zzz.c o proxy Warning: Suggest parentheses around assignment used as truth value if ( Sock=accept(listenSock,.) == -1 ){ 演算順位のミスに注意! if ( (Sock=accept(listenSock,.)) == -1 ){ if ( Sock =! 0){ 演算子の記載ミスに注意 ( =! ではなく!= ) if( Sock!= 0 ){ 2
Linux コマンド ( 最低限 ) ディレクトリの中身を表示など $ ls la ディレクトリの中身を表示したい時 $ cd /etc/ ディレクトリの移動 $ pwd 現在いるディレクトリを表示 ファイルの中身を見る ( 終了する時はq) $ more xxxx $ less xxxx $ lv xxxx ファイル, ディレクトリ操作 $ cp aaa.txt target.txt ファイルのコピー $ rm test.exe ファイルの削除 $ mv target.txt xxx.txt ファイル名の変更 $ mkdir public_html ディレクトリの作成 $ rmdir public_html ディレクトリの削除 Linuxを終了, 再起動 # shutdown h now 終了 # reboot 再起動 3
Linux コマンドチートシート ( カンペ ) http://www.yotabanana.com/misc/fwunixref_ja.pdf 4
http://gigazine.net/news/20070926_linux_structure/ Linux ディレクトリ構造 青色 : ディレクトリ赤色 : ファイル黒色 : 説明 5
コンパイル時のオプション 警告はできるだけ除去しましょう gcc Wall ansi O pedantic zzz.c o proxy マルチスレッドプログラムなどの場合 gcc lpthread zzz.c o proxy 余談 ) コンパイラ ( アセンブラ ) について http://edu.inf.shizuoka.ac.jp/lecture/2012/sw1/ 6
シグナルハンドラについて singal.h を読み込む main() で signal(sigint, xxxxx); xxxxx 関数で適切な処理を記述 ソケットディスクリプタを close() する前に, きちんと相手にソケットディスクリプタを close() することを伝えておく! 相手からその旨を受け取ったら, こちらも相手とつないでいるソケットディスクリプタを正常終了させる ( そうしないと TCP の場合, 片方に口が残ったままで, 中のデータを取り出しきれない状況に ) 7
デバッグ方法について ソケットが正常に close できたか分からない とか エラー処理関数を使ったエラー処理 error.h エラー番号とエラーメッセージの対応関係が記載 strerror() を使ったエラー出力 if((fp = fopen( hoge.txt, r )) == NULL){ fprintf(stderr, File open: %s n, strerror(errno)); exit(1); } perror() を使ったエラー出力 if((fp = fopen("hoge.txt", "a")) == NULL){ perror("file open: "); exit(1); } 出力例 ) File open: No such file or directory システムコールが失敗した場合, 通常は返り値として -1 が返り, errno にエラーを識別する値が設定 多くのライブラリ関数も同様の動作で,perror() は, このエラーコードを可読なメッセージへ変換してくれる 8
#ifdef, #ifndef プリプロセッサ ( 通常は広義のコンパイラが兼ねる ) ソースプログラムをコンパイルする前に実施される前処理 ( プリプロセス ) を行うプログラム 例 1) デバッグ時の定石 #define DEBUG... #ifdef DEBUG printf( Debug: x=%d n, x); #endif 例 2) 重複定義エラーを防ぐ定石 #ifndef MyHeaderFile /* ヘッダーの最初 */ #define MyHeaderFile /* インクルードファイルの記述 */ #endif /* ヘッダーの最後 */ 9
Linux カーネルの構造 ( 概要 ) システムコールインタフェース Terminal 回線規律 キャラクタデバイスドライバ Linux オペレーティングシステム I/O コンポーネント 仮想ファイルシステム Socket ネットワークプロトコル ネットワークデバイスドライバ ファイルシステム ジェネリックブロック層 I/O スケジューラ ブロックデバイスドライバ メモリ管理コンポーネント 仮想メモリ ページングページ交換 ページキャッシュ プロセス管理コンポーネント シグナルハンドリング プロセス / スレッド作成, 終了 CPU スケシ ューリンク 割り込み / 切り替え処理 キーホ ート 等 NIC 等 HDD 等 メインメモリ CPU 10
exec() と fork() によるプロセスの変化 プロセス PID = X プログラム = A exec() プロセス PID = X プログラム = B 親プロセス PID = X プログラム = A 親プロセス PID = X プログラム = A fork() 子プロセス PID = Y プログラム = A (a)exec() の場合 (b)fork() の場合 11
http://itpro.nikkeibp.co.jp/article/column/20071031/285990/ ソケットディスクリプタのイメージ 通信用のファイルディスクリプタ ディスクリプタ : 単なる整数, プロセス毎に管理 糸電話の口 ( 紙コップ ) のようなもの クライアント サーバーと通信するソケット X 1listen(A) A 2X=connect() B 3B=accept(A) サーバー 接続待ちソケット クライアントと通信するソケット ^Cの時 close(x) サーバーからの切断要求時 close(x) クライアントからの切断要求時 close(b) ^Cの時 close(a) close(b) listen() で接続処理を受け入れ可能な最大数は SOMAXCONN で指定例 ) http://x68000.q-e-d.net/~68user/net/echo-3.html 12
戻り値を無視しないように! ライブラリ関数の戻り値 ( リターンステータス ) を無視すると, 関数が失敗したことや部分的にしか成功していないことを見逃す恐れがある 結果としてエラーを増殖させ, 問題の特定を困難に! 例 1) send() の戻り値は? -1: 失敗が発生した場合 (errno 変数で理解可能 ) n: 送信された文字数 例 2) read() の戻り値は? -1: 失敗が発生した場合 (errno 変数で理解可能 ) n: 送信された文字数 0: ストリームソケットの接続相手が正しく終了した場合 13
SO_REUSEADDR について bind() で, ポート番号をサーバに関連付け TIME_WAIT 状態のポートであっても bind() できるようにする setsockopt() で,SO_REUSEADDR を指定 頻繁にソケットを開いたり閉じたりするようなシステムでは, TCP を利用するより UDP を利用するほうがよい BSD 系と Linux 系実装の違い http://umezawa.dyndns.info/wordpress/?p=2609 仮想環境のエミュレーション方法も関係するかも 14
getopt() argc や argv は使いこなせるようになった? 引数の数, その内容 様々なオプションを指定するには? >./getoptex -x -y -z -f filename -n 1200 file1 file2 file3 #include <unistd.h> /* UNIX 標準関係 */ while((c=getopt(argc, argv, xyzf:n: ))!=-1){ switch (c ){ case x : fprintf(stdout, -x オプション n ); break; case y : fprintf(stdout, -x オプション n ); } 15
select() でよくある不具合 クライアント, サーバ, どちらかのプログラムで無限ループ (select() で止まってくれない ) ソケットディスクリプタからずっと読み込み続けてしまう... 反対側で, ソケットディスクリプタを shutdown() してしまってないですか? select() の引数は必ず毎回再設定が必要! FD_ZERO(), FD_SET(),..., timeout = xxx とか タイムアウトした時は,continue させよう if (select( )<=0) continue; 16
ソケット関係のデバッグ netstat で状態を確認 netstat -n ESTABLISHED を 1 秒おきに表示 netstat -anp 待ち受け状態のポートと対応プロセスを表示 など パケットをキャプチャして分析 tcpdump, wireshark など ( 第二部で利活用 ) 暗号化されていなければペイロード部分 ( アプリケーションのデータ部分 ) を覗き見れるので, 意図した文字列を送受信しているのか分析可能 など 17