サーバーを作ろう<br />PHP でやるお(^ω^)<br />
目次<br />勉強しよう<br />TCP/IP<br />Socket API<br />クライアントとサーバー<br />設計しよう<br />サーバーの多重化<br />ウェブプログラマが何故サーバーを作るの?<br />
TCP/IP<br />ストリーム型の通信プロトコル<br />送ったら、送った順に届く<br />順序を持った可変長バイト列(文字列に変換しやすい!)として送ったり、受け取ったりできるのでプログラミングしやすい<br />ちゃんと届けられる<...
TCP/IP<br />送ったら送った順に届く<br />$fp = stream_socket_client('tcp://www.nicovideo.jp:80');<br />fwrite($fp, "GET / HTTP/1.0rn")...
送ったら送った順に届く<br />HTML がそのまま読めるよ<br />www.nicovideo.jp<br />送ったら<br />送った順に届く<br />PHP<br />Web Server<br />HTTP/1.1 200 OK...
TCP/IP<br />ちゃんと届けられる<br />$fp = stream_socket_client('tcp://www.nicovideo.jp:80', $errno, $errstr);<br />if ($fp=== false...
ちゃんと届けられる<br />ちゃんと届いてるみたいだな<br />www.nicovideo.jp<br />PHP<br />Web Server<br />GET / HTTP/1.0<br />Host: www.nicovideo.j...
TCP/IP<br />考えてみよう<br />ストリーム型じゃない通信プロトコルってどんなのだろう<br />TCP/IP 以外のストリーム型通信プロトコルを考えてみよう<br />
Socket API<br />TCP/IP などで通信相手と接続するためのライブラリが socket<br />接続後は、ファイルに対する読み書きの関数がそのまま使える<br />
ファイル操作の関数が使える<br />ソケットから読む<br />ファイルから読む<br />$fp = stream_socket_client(<br />             'tcp://www.nicovideo.jp:80');...
Socket API<br />考えてみよう<br />なんで、通信なのにファイルで抽象化してるんだろう?<br />
クライアントとサーバー<br />接続する側をクライアントと言う<br />接続を待つ側をサーバーと言う<br />それぞれで、接続が確立するまでのコードが違う<br />
作ってみよう<br />Mecabで形態素解析して、結果を返すサーバーと、そのクライアントを作る<br />Mecabのインストール<br />sudoapt-get install mecab # mecabプログラム<br />sudoap...
クライアント側のコード<br />繋ぐだけ<br />エラー処理とかは各自勉強してね<br />$fp = stream_socket_client('tcp://127.0.0.1:1111');<br />fwrite($fp, json_...
サーバー側のコード<br />接続を待って、 接続を確立する<br />エラー処理とかは各自勉強してね<br />$server = stream_socket_server('tcp://127.0.0.1:1111');<br />whil...
サーバー側の処理の多重化<br />前の例では、サーバー側のコードは、常に一つのクライアントに対しての処理しかしない<br />複数のクライアントに対して処理をしたい場合は、以下のいずれかの方法でサーバーの処理を多重化する必要がある<br />...
フォークによる多重化<br />プロセスを分身させる。<br />メモリは COW で節約されるけど、スレッドと比べてメモリを食う<br />処理ごとに値が独立してるので、プログラミングが楽<br />$server = stream_sock...
スレッドによる多重化<br />PHP では出来ない??<br />フォークするより、省メモリ。<br />とはいえ、スタック領域などのメモリは食う。<br />マルチスレッドプログラミング難しい><<br />
イベントループによる多重化<br />フォークや、スレッドと比べて軽量<br />$server = stream_socket_server('tcp://127.0.0.1:1111');<br />stream_set_blocking(...
イベントループによる多重化<br />function ev_accept($server, $flag, $base) {<br />  global $id;<br />  global $fps;<br />  global $bufs;...
イベントループによる多重化<br />function ev_error($buf, $error, $id) {<br />  global $id;<br />  global $fps;<br />  global $bufs;<br /...
ウェブプログラマが何故サーバーを作るの?<br />プロセスやマシンに縛られるのはやめよう<br />1プロセスに拘らなくなる<br />プログラミング言語に拘らなくてよくなる<br />使いたいライブラリがあったら、なんでも使える。ソケットで...
Upcoming SlideShare
Loading in...5
×

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

28,304

Published on

シス創勉強会資料

0 Comments
24 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
28,304
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
118
Comments
0
Likes
24
Embeds 0
No embeds

No notes for slide

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

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

    Clipping is a handy way to collect important slides you want to go back to later.

×