システムプログラミング演習 田浦
演習を通して学んでほしいこと ネットワークプログラミング HTTP (webのプロトコル) HTML (ほんの少し) スレッドプログラミング インターネットの基本 ソケット HTTP (webのプロトコル) HTML (ほんの少し) スレッドプログラミング Webサーバの基本的な構成(ミニチュア)
情報源 UNIX : manページ Windows : MSDNライブラリ man recv man 2 recv man 3 recv Online 図書からCDを借りてインストール
インターネットの復習 IPアドレス IP (Internet Protocol) 133.11.23.10 etc. IP (Internet Protocol) IPアドレスを指定すると(世界中どこへでも)パケットをがんばって届けてくれる(厳密にはウソ.後ほど) 失敗あり TCP (transfer control protocol) IPの上の“reliable”なレイヤ ポート番号による複数の入り口・出口管理 数え切れないアプリがこれを利用している
IPアドレスを調べてみよう Win: ipconfig Unix: /sbin/ifconfig –a 接続時に自動的に重複なく割り当てられていることがほとんど(DHCP)
さっきのはウソ 一部のアドレスは「ローカルアドレス」 LANの外からはつなげない 10.0.0.0 – 10.255.255.255 172.16.0.0 – 172.31.255.255 192.168.0.0 – 192.168.255.255 LANの外からはつなげない でもLANの定義は微妙…
ソケット プロセス間通信(含むインターネット通信)のためのAPI 本演習ではソケットをTCPを用いたインターネット通信のために使う
基本概念 クライアント(=電話をかける人) s = socket(…); connect(つなぎたいIPアドレスとポート); /* 電話かける */ send/recv(s, …); サーバ(=電話を受ける人) s = socket(…); sにIPアドレスとポートを割り当て(電話番号登録); new_s = accept(s); /* 待ち受け */ send/recv(new_s, …);
ソケット練習課題 送られてきた文字列を表示するだけのサーバ ブラウザがどんな文字列を送ってきているのかを調べるのに役に立つ
HTTP/HTML ブラウザとWebサーバのやり取り(のほんの一部) テキスト・参考書を読むのもよいが, HTTP (Hypter Text Transfer Protocol) HTML (Hyper Text Markup Language) テキスト・参考書を読むのもよいが, ブラウザは既にHTTPのリクエストをしゃべる サーバは既にHTTPのリプライをしゃべる 先の課題でブラウザのメッセージを表示できる telnetコマンドでサーバの返事を表示できる
先週の復習 サーバ クライアント socket socket bind & listen connect accept send recv GET <パス> HTTP/1.0 … <空行> send recv HTTP/1.1 200 OK … <空行> <ページの内容> send recv
入力パス名と状態遷移 セッション(ゲーム)ID new game 6 digits 8 digits … / remember 78478931 /new_n/ セッション(ゲーム)ID next 1 2 … END /xxx_S/ wrong! /xxx_?/ (不正解) congrat! /xxx_X/ (正解) /xxx_n/ (正解)
複数ゲームの同時進行が可能な構成 /new_n/ / /new_n/ new game 6 digits 8 digits …
スレッドの概念 スレッド: プログラムの文面を順に実行する「主体」 main() { … } で … が実行されるのは,OSがmainを実行するスレッドを生成して実行しているから プログラム中でスレッドを生成するAPIが存在する
スレッドAPI UNIX: POSIXスレッド(Pthreads) Windows: Win32スレッド 概念はほとんど同じ(見た目はソケットほど似てはいないが…) 生成 同期(タイミングの制御) 以下,Pthreadsに準じて説明
生成 pthread_create(…, f, x, …); つまり, pthread_create(…, f, x, …); <…> で,f (x)と<…>が並行に実行される f (x)と<…>はメモリを共有する
“並行に”実行されるとは? たくさんCPUがあれば本当に「同時に」実行される 一般には,「あるだけのCPU」を「存在するだけのスレッド」がかわりばんこに使う(OSの制御) プログラムは「かわりばんこ」を意識しなくてよい
プログラムの書かれ方 実際 CPU
スレッド利用上の大注意 次の結果は? initially: x = 1; スレッド1: f () { x = x * 10; } スレッド2: g () { x = x * 5; }
同期の概念 スレッドの「実行タイミング」の制御 両者とも頻繁に用いられ,本課題でも使う 排他制御: 「これ」と「あれ」を同時に実行してはいけない(どちらが先でも良い) 生産者消費者同期: 「これ」がおわってから「あれ」を実行すべし 両者とも頻繁に用いられ,本課題でも使う
排他制御 pthread_mutex_t m; pthread_mutex_init(&m); スレッドA: … pthread_mutex_lock(&m); pthread_mutex_unlock(&m); … スレッドB: … pthread_mutex_lock(&m); pthread_mutex_unlock(&m);
生産者消費者同期 疲れるのでまた来週(テキストを読んでおいてください)
本課題でのスレッドの利用 全てのリクエスト(acceptからのreturn)に「そのリクエスト処理」スレッドを生成 / : これまでどおり /new_yyy/ : (新しいセッション)だったら,そのスレッドは,「そのセッション専門スレッド」になり,以降そのセッションへのメッセージを待つ /xxx_yyy/ : セッションID xxx に対応するスレッドに yyy を渡す
/xxx_yyy/ / /new_?/ mainスレッド accept セッションスレッド xxxにメッセージ yyyをとどける これまで通り /new_?/ セッションスレッド wait_for_msg 正しい受け渡しの ための同期!
本日のメニュー 生産者消費者同期 おまけ: 本物のwebサーバとの違い
Windows Socketの初期化 WORD wVersionRequested = MAKEWORD( 2, 2 ); WSADATA wsaData[1]; if (0 != WSAStartup(wVersionRequested, wsaData)){ /* 失敗! ありえない! */ }
生産者消費者同期とは スレッドSの操作Aがおわるまで,スレッドTの操作Bを待たせたい 典型的な状況 but, 上に限らず頻出する状況 result = 10; … = result; B
本課題の生産者消費者同期 注: 実は2つの同期の複合 GはRが書く前に読んではいけない メインスレッド G: セッション(1スレッド/ゲーム) create 注: 実は2つの同期の複合 GはRが書く前に読んではいけない RはGが(一つ前のデータを)読む前に(次のデータを)書いてはいけない 「有限バッファ」問題 R: リクエスト処理 1スレッド/リクエスト put_data get_data
条件変数(condition variable) 一般的に,「ある条件が成立するまで待つ」を実現するprimitive 例 (いくらでも…) x + y > 0 になるまで待つ Q (queueオブジェクト)が空でなくなるまで待つ f (x, y, z)が成立するまで待つ 要するに何にでも使える強力primitive
基本フォーム C(x, y, z)が成立するまで待ちたい時: pthread_mutex_lock(m); while (!C(x, y, z)) { mをunlockし,ブロックする; 起きたらまたmをlock; } x, y, zなどをいじる 必要なら,他の待ってる人たちを起こす pthread_mutex_unlock(m);
条件変数API pthread_cond_t c; pthread_mutex_t m; pthread_cond_init(&c); pthread_cond_wait(&c, &m); mをunlockし,cの上でブロックする.起こされたらまたmをlockする pthread_cond_broadcast(&c); cでブロックしている人全員をたたき起こす
有限バッファ with 条件変数 容量1の有限バッファ typedef struct { int data; int full; mutex_t m; cond_t c } bb;
有限バッファ with 条件変数 (2) bb_get(bb * b) { lock(&b->m); while(!b->full) wait(&b->c); t = b->data; b->full = 0; broadcast(&b->c); return t; }
有限バッファ with 条件変数 (3) bb_put(bb * b, int x) { lock(&b->m); while(b->full) wait(&b->c); b->data = x; b->full = 1; broadcast(&b->c); }
関連primitive: セマフォ mutexの一般化(n人まで同時利用可能) Windows (not in Pthreads) HANDLE s = CreateSemaphore(…); wait: WaitForSingleObject(s, …); WaitForMultipleObjects(…); signal: ReleaseSemaphore(s, …);
補足(1) セッションID セッションIDの簡単な生成法=スレッドのスタック上の変数のアドレス do_session() { char dummy; long session_id = (long)&dummy; … }
補足(2) 有限バッファメモリ管理 typedef struct { … } session_table_entry; session_table_entry session_table[MAX_SESSIONS]; 操作: 新しいsessionの登録 与えられたsession IDのentry検索 いたるところに同期が必要 本課題ではむなしいが,10000 req/secのサーバを作っている気分で
おまけ(1) 巷のwebサーバとの違い 本物のwebサーバは 状態をメモリに残さない.データベースと連携.セッションIDをcookieとしてブラウザに送り返す 基本サービス以外は外部プログラム(CGI)を起動する(拡張性) スレッドプール(同時処理に上限) スレッドの変わりにプロセスを使うこともある
おまけ(2): VMWare/Linux オペレーション Linux in VMWareをインターネットにつなげる VMWareのネットワーク構成 IP接続 WWWブラウザ メール Linux in VMWare ホストWindowsとの通信 ホスト -> ゲストの接続 ファイルコピー ファイル共有
VMWareのネットワーク構成 残念なこと 無線LANではBridgedでは使えない (外向き接続) (内向き接続) Bridged インターネット LAN (ローカルアドレス)またはインターネット (グローバルアドレス) NAT ホスト Host-Only 残念なこと 無線LANではBridgedでは使えない
診断手順 /sbin/ifconfig –a ping TCP接続 ブラウザ->webサーバ telnet->何かのサーバ(web, メール, etc.) 本演習で作ったプログラム!
ダメなとき /sbin/ifconfig –aでIPアドレスが変(0.0.0.0とかゴミっぽい) 直らなければ? /sbin/ifdown –a /sbin/ifup –a 直らなければ? NAT/Host-Onlyでやってみる 複数の同時接続を許すISPか? 許さなければBridgedは無理
ダメなとき pingが通らない 近場(=ホストOS)に通す ホストOS (Windows)のアドレスはipconfigでチェック Bridged, NAT, Host-Onlyで見るべき値が違う 近場に通らなければLinuxの問題か? 近場に通るがインターネット(e.g., yahoo)に通らない Host-Onlyじゃない? ファイアウォールなど?
pingが通るけどWWWが動かない あまりない…
pingが通るがメールが動かない まずメールの設定をせよ emacs + mew 設定方法は後日HPにのせます
設定したがなぜか動かない 色々な理由がある SPAMとの戦い メールの仕組みを多少知っておいたほうが良い
メールの仕組み メーラ (mew, outlook) 送信(認証なし) 受信 (認証あり) ポート25 SMTPサーバ POP/IMAPサーバ ポート110 (POP)
メールが送れないありがちな理由 SMTPサーバ設定ミス 受け取りを拒否される telnet <サーバ名> 25でつながるか? ありがち: SMTPサーバが,LAN外からの送信を拒否している × 大学 -> ISPのメールサーバ × ISP -> 大学のメールサーバ
メールが受け取れないありがちな理由 POP/IMAPサーバ設定ミス LAN外からの危ない認証法拒否 telnet <サーバ名> 110 (POP) telnet <サーバ名> 143 (IMAP) でつながるか LAN外からの危ない認証法拒否 ×大学 <- ISP POPサーバ × ISP <- 大学 POPサーバ