Upload
-
View
26.404
Download
0
Embed Size (px)
DESCRIPTION
シス創勉強会資料
Citation preview
TCP/IP
• ストリーム型の通信プロトコル– 送ったら、送った順に届く• 順序を持った可変長バイト列(文字列に変換しや
すい!)として送ったり、受け取ったりできるのでプログラミングしやすい
– ちゃんと届けられる• 相手が通信可能な状態かどうか分かる
– 「相手が通信可能な状態じゃなかったら」という処理を書ける
• 届いたかどうか分かる– 「届かなかったら」という処理を書ける
TCP/IP
• 送ったら送った順に届く
$fp = stream_socket_client('tcp://www.nicovideo.jp:80');
fwrite($fp, "GET / HTTP/1.0\r\n");fwrite($fp, "Host: www.nicovideo.jp\r\n\r\n");
echo stream_get_contents($fp);
fclose($fp);
送ったら送った順に届く
TCP/IPTCP/IP
www.nicovideo.jp
PHP Web Server
HTTP/1.1 200 OK<html>…</html>
HTTP/1.1 200 OK<html>…</html>
送ったら送った順に届く
HTML がそのまま読めるよ
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.0\r\n") === false) { throw new Exception($php_errormsg);}
if (fwrite($fp, "Host: www.nicovideo.jp\r\n\r\n") === false) { throw new Exception($php_errormsg);}
echo stream_get_contents($fp);
fclose($fp);
ちゃんと届けられる
TCP/IPTCP/IP
www.nicovideo.jp
PHP Web Server
届いた届いた
GET / HTTP/1.0Host: www.nicovideo.jp
GET / HTTP/1.0Host: www.nicovideo.jp
ちゃんと届いてるみたいだ
な
ファイル操作の関数が使える
$fp = stream_socket_client( 'tcp://www.nicovideo.jp:80');fwrite($fp, "GET / HTTP/1.0\r\n");fwrite($fp, "Host: www.nicovideo.jp\r\n\r\n");while (fgets($fp) !== "\r\n") { }
$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;まったく同じコードを使える
ソケットから読む ファイルから読む
作ってみよう• Mecab で形態素解析して、結果を返す
サーバーと、そのクライアントを作る• Mecab のインストール
sudo apt-get install mecab # mecab プログラムsudo apt-get install libmecab-dev # mecab.so を作るのに必要sudo apt-get install mecab-naist-jdic mecab-jumandic-utf8 # mecab の UTF-8 の辞書sudo apt-get install build-essentials # php 拡張をコンパイルするためのツール群sudo pear channel-discover pecl.opendogs.orgsudo pear remote-list -c opendogssudo pear install opendogs/mecab-beta# 以下のファイルに extension=mecab.so を追加sudo vim /etc/php5/cli/php.ini
クライアント側のコード• 繋ぐだけ– エラー処理とかは各自勉強してね
$fp = stream_socket_client('tcp://127.0.0.1:1111');
fwrite($fp, json_encode($argv[1]) . "\r\n");$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))) . "\r\n"); }
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))) . "\r\n"); } fclose($fp); exit; }}fclose($server);
イベントループによる多重化• フォークや、スレッドと比べて軽量
$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))) . "\r\n"); }}