• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
サーバーを作ろう (毎週のハンズオン勉強会の資料)
 

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

on

  • 25,848 views

シス創勉強会資料

シス創勉強会資料

Statistics

Views

Total Views
25,848
Views on SlideShare
24,885
Embed Views
963

Actions

Likes
24
Downloads
114
Comments
0

16 Embeds 963

http://paper.li 704
http://kawakami.ut-gym.jp 80
http://ut-gym.jp 41
http://twitter.com 40
http://dots.nt-dev.info 38
https://twitter.com 15
http://us-w1.rockmelt.com 13
http://tweetedtimes.com 9
http://dots-web.nt-dev.info 8
http://nuevospowerpoints.blogspot.com 6
http://utgym.localhost 2
http://twicli.neocat.jp 2
http://a0.twimg.com 2
http://b.hatena.ne.jp 1
http://dev.ut-gym.jp 1
http://localhost 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

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

    • サーバーを作ろう
      PHP でやるお(^ω^)
    • 目次
      勉強しよう
      TCP/IP
      Socket API
      クライアントとサーバー
      設計しよう
      サーバーの多重化
      ウェブプログラマが何故サーバーを作るの?
    • TCP/IP
      ストリーム型の通信プロトコル
      送ったら、送った順に届く
      順序を持った可変長バイト列(文字列に変換しやすい!)として送ったり、受け取ったりできるのでプログラミングしやすい
      ちゃんと届けられる
      相手が通信可能な状態かどうか分かる
      「相手が通信可能な状態じゃなかったら」という処理を書ける
      届いたかどうか分かる
      「届かなかったら」という処理を書ける
    • 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);
    • 送ったら送った順に届く
      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
    • 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);
    • ちゃんと届けられる
      ちゃんと届いてるみたいだな
      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
      届いた
      届いた
    • TCP/IP
      考えてみよう
      ストリーム型じゃない通信プロトコルってどんなのだろう
      TCP/IP 以外のストリーム型通信プロトコルを考えてみよう
    • Socket API
      TCP/IP などで通信相手と接続するためのライブラリが socket
      接続後は、ファイルに対する読み書きの関数がそのまま使える
    • ファイル操作の関数が使える
      ソケットから読む
      ファイルから読む
      $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;
      まったく同じコードを使える
    • Socket API
      考えてみよう
      なんで、通信なのにファイルで抽象化してるんだろう?
    • クライアントとサーバー
      接続する側をクライアントと言う
      接続を待つ側をサーバーと言う
      それぞれで、接続が確立するまでのコードが違う
    • 作ってみよう
      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
    • クライアント側のコード
      繋ぐだけ
      エラー処理とかは各自勉強してね
      $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);
    • サーバー側のコード
      接続を待って、 接続を確立する
      エラー処理とかは各自勉強してね
      $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);
    • サーバー側の処理の多重化
      前の例では、サーバー側のコードは、常に一つのクライアントに対しての処理しかしない
      複数のクライアントに対して処理をしたい場合は、以下のいずれかの方法でサーバーの処理を多重化する必要がある
      フォークによる多重化
      イベントループによる多重化
      スレッドによる多重化
    • フォークによる多重化
      プロセスを分身させる。
      メモリは 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);
    • スレッドによる多重化
      PHP では出来ない??
      フォークするより、省メモリ。
      とはいえ、スタック領域などのメモリは食う。
      マルチスレッドプログラミング難しい><
    • イベントループによる多重化
      フォークや、スレッドと比べて軽量
      $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();
    • イベントループによる多重化
      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;
      }
    • イベントループによる多重化
      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");
      }
      }
    • ウェブプログラマが何故サーバーを作るの?
      プロセスやマシンに縛られるのはやめよう
      1プロセスに拘らなくなる
      プログラミング言語に拘らなくてよくなる
      使いたいライブラリがあったら、なんでも使える。ソケットでプロセスを繋げばいい
      1マシンに拘らなくなる
      OS に拘らなくてもよくなる
      負荷分散も自由自在