Your SlideShare is downloading. ×
  • Like
サーバーを作ろう (毎週のハンズオン勉強会の資料)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

サーバーを作ろう (毎週のハンズオン勉強会の資料)

  • 25,743 views
Published

シス創勉強会資料

シス創勉強会資料

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
25,743
On SlideShare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
117
Comments
0
Likes
24

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. サーバーを作ろう
    PHP でやるお(^ω^)
  • 2. 目次
    勉強しよう
    TCP/IP
    Socket API
    クライアントとサーバー
    設計しよう
    サーバーの多重化
    ウェブプログラマが何故サーバーを作るの?
  • 3. TCP/IP
    ストリーム型の通信プロトコル
    送ったら、送った順に届く
    順序を持った可変長バイト列(文字列に変換しやすい!)として送ったり、受け取ったりできるのでプログラミングしやすい
    ちゃんと届けられる
    相手が通信可能な状態かどうか分かる
    「相手が通信可能な状態じゃなかったら」という処理を書ける
    届いたかどうか分かる
    「届かなかったら」という処理を書ける
  • 4. TCP/IP
    送ったら送った順に届く
    $fp = stream_socket_client('tcp://www.nicovideo.jp:80');
    fwrite($fp, "GET / HTTP/1.0rn");
    fwrite($fp, "Host: www.nicovideo.jprnrn");
    echo stream_get_contents($fp);
    fclose($fp);
  • 5. 送ったら送った順に届く
    HTML がそのまま読めるよ
    www.nicovideo.jp
    送ったら
    送った順に届く
    PHP
    Web Server
    HTTP/1.1 200 OK
    <html>…</html>
    HTTP/1.1 200 OK
    <html>…</html>
    TCP/IP
    TCP/IP
  • 6. TCP/IP
    ちゃんと届けられる
    $fp = stream_socket_client('tcp://www.nicovideo.jp:80', $errno, $errstr);
    if ($fp=== false) {
    throw new Exception($errstr);
    }
    if (fwrite($fp, "GET / HTTP/1.0rn") === false) {
    throw new Exception($php_errormsg);
    }
    if (fwrite($fp, "Host: www.nicovideo.jprnrn") === false) {
    throw new Exception($php_errormsg);
    }
    echo stream_get_contents($fp);
    fclose($fp);
  • 7. ちゃんと届けられる
    ちゃんと届いてるみたいだな
    www.nicovideo.jp
    PHP
    Web Server
    GET / HTTP/1.0
    Host: www.nicovideo.jp
    GET / HTTP/1.0
    Host: www.nicovideo.jp
    TCP/IP
    TCP/IP
    届いた
    届いた
  • 8. TCP/IP
    考えてみよう
    ストリーム型じゃない通信プロトコルってどんなのだろう
    TCP/IP 以外のストリーム型通信プロトコルを考えてみよう
  • 9. Socket API
    TCP/IP などで通信相手と接続するためのライブラリが socket
    接続後は、ファイルに対する読み書きの関数がそのまま使える
  • 10. ファイル操作の関数が使える
    ソケットから読む
    ファイルから読む
    $fp = stream_socket_client(
                 'tcp://www.nicovideo.jp:80');
    fwrite($fp, "GET / HTTP/1.0rn");
    fwrite($fp, "Host: www.nicovideo.jprnrn");
    while (fgets($fp) !== "rn") { }
    $content = stream_get_contents($fp);
    if (!mb_check_encoding($content, 'UTF-8')) {
    throw new Exception('Invalid encoding!');
    }
    fclose($fp);
    libxml_use_internal_errors(true);
    $doc = new DOMDocument();
    $doc->loadHTML($content);
    libxml_clear_errors();
    echo $doc->getElementsByTagName('title')
          ->item(0)->textContent;
    $fp = fopen('test.html', 'r');
    $content = stream_get_contents($fp);
    if (!mb_check_encoding($content, 'UTF-8')) {
    throw new Exception('Invalid encoding!');
    }
    fclose($fp);
    libxml_use_internal_errors(true);
    $doc = new DOMDocument();
    $doc->loadHTML($content);
    libxml_clear_errors();
    echo $doc->getElementsByTagName('title')
          ->item(0)->textContent;
    まったく同じコードを使える
  • 11. Socket API
    考えてみよう
    なんで、通信なのにファイルで抽象化してるんだろう?
  • 12. クライアントとサーバー
    接続する側をクライアントと言う
    接続を待つ側をサーバーと言う
    それぞれで、接続が確立するまでのコードが違う
  • 13. 作ってみよう
    Mecabで形態素解析して、結果を返すサーバーと、そのクライアントを作る
    Mecabのインストール
    sudoapt-get install mecab # mecabプログラム
    sudoapt-get install libmecab-dev # mecab.so を作るのに必要
    sudoapt-get install mecab-naist-jdic mecab-jumandic-utf8 # mecabの UTF-8 の辞書
    sudoapt-get install build-essentials # php拡張をコンパイルするためのツール群
    sudopear channel-discover pecl.opendogs.org
    sudopear remote-list -c opendogs
    sudopear install opendogs/mecab-beta
    # 以下のファイルに extension=mecab.so を追加
    sudovim /etc/php5/cli/php.ini
  • 14. クライアント側のコード
    繋ぐだけ
    エラー処理とかは各自勉強してね
    $fp = stream_socket_client('tcp://127.0.0.1:1111');
    fwrite($fp, json_encode($argv[1]) . "rn");
    $list = json_decode(fgets($fp, 1024));
    var_dump($list);
    fclose($fp);
  • 15. サーバー側のコード
    接続を待って、 接続を確立する
    エラー処理とかは各自勉強してね
    $server = stream_socket_server('tcp://127.0.0.1:1111');
    while (true) {
    $fp = stream_socket_accept($server);
    while (!feof($fp)) {
    $str = fgets($fp, 1024);
    fwrite($fp, json_encode(mecab_split(json_decode($str))) . "rn");
    }
    fclose($fp);
    }
    fclose($server);
  • 16. サーバー側の処理の多重化
    前の例では、サーバー側のコードは、常に一つのクライアントに対しての処理しかしない
    複数のクライアントに対して処理をしたい場合は、以下のいずれかの方法でサーバーの処理を多重化する必要がある
    フォークによる多重化
    イベントループによる多重化
    スレッドによる多重化
  • 17. フォークによる多重化
    プロセスを分身させる。
    メモリは COW で節約されるけど、スレッドと比べてメモリを食う
    処理ごとに値が独立してるので、プログラミングが楽
    $server = stream_socket_server('tcp://127.0.0.1:1111');
    while (true) {
    $fp = stream_socket_accept($server);
    if (!pcntl_fork()) {
    while (!feof($fp)) {
    $str = fgets($fp, 1024);
    fwrite($fp, json_encode(mecab_split(json_decode($str))) . "rn");
    }
    fclose($fp);
    exit;
    }
    }
    fclose($server);
  • 18. スレッドによる多重化
    PHP では出来ない??
    フォークするより、省メモリ。
    とはいえ、スタック領域などのメモリは食う。
    マルチスレッドプログラミング難しい><
  • 19. イベントループによる多重化
    フォークや、スレッドと比べて軽量
    $server = stream_socket_server('tcp://127.0.0.1:1111');
    stream_set_blocking($server, 0);
    $base = event_base_new();
    $event = event_new();
    event_set($event, $server, EV_READ | EV_PERSIST, 'ev_accept', $base);
    event_base_set($event, $base);
    event_add($event);
    event_base_loop($base);
    $id = 0;
    $fps = array();
    $bufs = array();
  • 20. イベントループによる多重化
    function ev_accept($server, $flag, $base) {
    global $id;
    global $fps;
    global $bufs;
    $fp = stream_socket_accept($server);
    stream_set_blocking($fp, 0);
    $id++;
    $buf = event_buffer_new($fp, 'ev_read', NULL, 'ev_error', $id);
    event_buffer_base_set($buf, $base);
    event_buffer_timeout_set($buf, 30, 30);
    event_buffer_watermark_set($buf, EV_READ, 0, 0xffffff);
    event_buffer_priority_set($buf, 10);
    event_buffer_enable($buf, EV_READ | EV_PERSIST);
    $fps[$id] = $fp;
    $bufs[$id] = $buf;
    }
  • 21. イベントループによる多重化
    function ev_error($buf, $error, $id) {
    global $id;
    global $fps;
    global $bufs;
    event_buffer_disable($bufs[$id], EV_READ | EV_WRITE);
    event_buffer_free($bufs[$id]);
    fclose($fps[$id]);
    unset($fps[$id], $bufs[$id]);
    }
    function ev_read($buf, $id) {
    global $id;
    global $fps;
    global $bufs;
    while ($str = event_buffer_read($buf, 1024)) {
    $fp = $fps[$id];
    fwrite($fp, json_encode(mecab_split(json_decode($str))) . "rn");
    }
    }
  • 22. ウェブプログラマが何故サーバーを作るの?
    プロセスやマシンに縛られるのはやめよう
    1プロセスに拘らなくなる
    プログラミング言語に拘らなくてよくなる
    使いたいライブラリがあったら、なんでも使える。ソケットでプロセスを繋げばいい
    1マシンに拘らなくなる
    OS に拘らなくてもよくなる
    負荷分散も自由自在