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 再起動 34
http://www.yotabanana.com/misc/fwunixref_ja.pdf
Linuxディレクトリ構造
5 http://gigazine.net/news/20070926_linux_structure/ 青色:ディレクトリ 赤色:ファイル 黒色:説明コンパイル時のオプション
•
警告はできるだけ除去しましょう
– 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オペレーティングシステム システムコールインタフェース I/Oコンポーネント コンポーネントメモリ管理 プロセス管理 コンポーネント キャラクタ デバイス ドライバ ブロック デバイス ドライバ ネットワーク デバイス ドライバ I/O スケジューラ ファイル システム ジェネリック ブロック層 ネットワーク プロトコル Socket Terminal キーボード等 NIC等 HDD等 仮想ファイルシステム 回線規律 ページング ページ交換 仮想メモリ ページ キャッシュ プロセス/ スレッド作成, 終了 シグナル ハンドリング CPU スケジューリング メインメモリ CPU 割り込み / 切り替え処理
Linuxカーネルの構造(概要)
[補足]
10プロセス PID = X プログラム = A プロセス PID = X プログラム = B exec() 親プロセス PID = X プログラム = A 親プロセス PID = X プログラム = A 子プロセス PID = Y プログラム = A fork() (a)exec()の場合 (b)fork()の場合
exec()とfork()によるプロセスの変化
[補足]
11ソケットディスクリプタのイメージ
• 通信用のファイルディスクリプタ – ディスクリプタ: 単なる整数,プロセス毎に管理 • 糸電話の口(紙コップ)のようなもの 12 A X ①listen(A) ②X=connect() ③B=accept(A) B close(A) close(B) ^Cの時 close(B) クライアントから の切断要求時 サーバー クライアント close(X) サーバーからの 切断要求時 close(X) ^Cの時 接続待ちソケット クライアントと通信するソケット サーバーと通信するソケット listen()で接続処理を受け入れ可能な最大数はSOMAXCONNで指定 例) http://x68000.q-e-d.net/~68user/net/echo-3.html http://itpro.nikkeibp.co.jp/article/COLUMN/20071031/285990/[補足]
戻り値を無視しないように!
•ライブラリ関数の戻り値(リターンステータス)を
無視すると,関数が失敗したことや部分的にし
か成功していないことを見逃す恐れがある
– 結果としてエラーを増殖させ,問題の特定を困難 に! – 例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