サーバの起動情報は、HTTP の POST メソッドで通知するとし、その管理はメタサーバ上の PHP スクリプトで行うとする。
サーバ起動情報の通知と取得
従って、HTTP プロトコルで指定アドレスに POST, GET でアクセスする機能が必要となる。また、サーバ一覧情報を生成する PHP スクリプトの仕様は以下の通りとする。
上記仕様を実装したものは、こんな感じ。
<?php /* オッニー、キ、ニ、、、オ。シ・ミセホエノヘ Satofumi KAMIMURA $Id$ */ require_once('includes/config.php'); if (isset($_POST['port']) && isset($_POST['people'])) { // ・オ。シ・ミ、ォ、鬢ホ host, port トフテホ、ンツク $recv_ticks = time(); $port = intval($_POST['port']); $people = intval($_POST['people']); $host = $_SERVER['REMOTE_ADDR']; if (!preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $host)) { exit; } // ・オ。シ・ミセノイテ $fd = fopen(DataFile, 'a'); if ($fd && flock($fd, LOCK_EX)) { fwrite($fd, $recv_ticks. "\t". $people. "\t". $port. "\t". $host. "\n"); flock($fd, LOCK_UN); } fclose($fd); exit; } else { // オッニー、キ、ニ、、、、ネサラ、・オ。シ・ミセミホマ $fd = fopen(DataFile, 'r'); if (!$fd || !flock($fd, LOCK_SH)) { exit; } $servers = array(); $now_ticks = time(); while ($info = fscanf($fd, "%d\t%d\t%d\t%s\n")) { list ($ticks, $people, $port, $host) = $info; if ($ticks + TimeoutSec > $now_ticks) { $servers[$port. "\t". $host] = $ticks. "\t". $people; } } flock($fd, LOCK_UN); fclose($fd); // ケケソキ $fd = fopen(DataFile, 'w'); if (!flock($fd, LOCK_EX)) { exit; } if (count($servers) <= 0) { // ・ケ・ネ、ャカホセ遉ホス靉 echo "\n"; } else { // ・ソ・、・爭「・ヲ・ネノセイチク螟ホハンツク・ケ・ネ、ンツク asort($servers); reset ($servers); while (list ($key, $val) = each ($servers)) { $people = split("\t", $val); $people = $people[1]; if ($people > 0) { echo $people. "\t". $key. "\n"; fwrite($fd, $val. "\t". $key. "\n"); } } } flock($fd, LOCK_UN); fclose($fd); } ?>
で、その実装のテストは、以下の通り。
<?php /* serverList.php 、ホ・ニ・ケ・ネ Satofumi KAMIMURA $Id$ */ define('TestHost', 'localhost'); define('TestURL', '/~satofumi/nettyping/test/serverList.php'); define('LocalHost', '127.0.0.1'); define('SomeHost', '127.0.0.1'); error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); require_once('phpunit/phpunit.php'); require_once('includes/postSendClass.php'); class ServerListTest extends TestCase { var $obj; var $url; // ・ウ・ケ・ネ・鬣ッ・ソ function ServerListTest($name) { $this->TestCase($name); $this->url = 'http://'. TestHost. TestURL; } // ・ニ・ケ・ネ、ホス魘ス function setUp() {} // ・ニ・ケ・ネ、ホスェホサ function tearDown() {} // ニノ、゜スミ、キサヒカォ、ノ、ヲ、ォ、ホウホヌァ function testNull() { $lines = file($this->url); $this->assertEquals(1, count($lines)); $this->assertEquals("\n", $lines[0]); } function check1stInfo() { // ニノ、゜スミ、キ、ニ。「・ヌ。シ・ソ、ャヘストフ、熙ォ、ホウホヌァ $lines = file($this->url); $this->assertEquals(1, count($lines)); $this->assertEquals("1\t57577\t". LocalHost. "\n", $lines[0]); } // 」アキワ、ホ・ヌ。シ・ソ、ミマソ、ヌ、ュ、ォウホヌァ function test1stPost() { $post = new PostSend; $post->add('host', LocalHost); $post->add('port', '57577'); $post->add('people', '1'); $post->send(TestHost, TestURL); $this->check1stInfo(); } // 」イキワ、ホ・ヌ。シ・ソ、ミマソ、ヌ、ュ、ォウホヌァ function test2ndPost() { $post = new PostSend; $post->add('host', SomeHost); $post->add('port', '57578'); $post->add('people', '1'); $post->send(TestHost, TestURL); // ニノ、゜スミ、キ、ニ。「・ヌ。シ・ソ、ャヘストフ、熙ォ、ホウホヌァ $lines = file($this->url); $this->assertEquals(2, count($lines)); $this->assertEquals("1\t57578\t". SomeHost. "\n", $lines[0]); $this->assertEquals("1\t57577\t". LocalHost. "\n", $lines[1]); } // 0 ソヘ、スタチ、ケ、ネ。「・ヌ。シ・ソ、ャコオ、ォウホヌァ function testNoPeople() { $post = new PostSend; $post->add('host', SomeHost); $post->add('port', '57578'); $post->add('people', '0'); $post->send(TestHost, TestURL); $this->check1stInfo(); } // ーヨク螟ヒ・ヌ。シ・ソ、ャコオ、ォウホヌァ function testTimeout() { sleep(1); $this->testNull(); } } ?> <html> <head> <title>ServerListTest</title> <STYLE TYPE="text/css"> <?php include ("stylesheet.css"); ?> </STYLE> </head> <body> <?php $suite = new TestSuite('ServerListTest'); $result = new PrettyTestResult; $suite->run($result); $result->report(); ?>
<? /* ・ヌ。シ・ソ、ホ POST チョ、ヤ、ヲ、ソ、皃ホ・ッ・鬣ケ Satofumi KAMIMURA $Id$ */ class PostSend { var $post_str; // ・ウ・ケ・ネ・鬣ッ・ソ function PostSend() { $this->post_str = ''; } // POST ・ッ・ィ・ケ・ネ、ホチョ function send($host, $page) { $request = 'POST '. $page. " HTTP/1.0\r\n". 'Host: '. $host. "\r\n". "Content-Type: application/x-www-form-urlencoded\r\n". 'Content-Length: '. strlen($this->post_str). "\r\n". "Accept: */*\r\n". "\r\n". $this->post_str. "\r\n". "\r\n"; $fp = fsockopen($host, 80, $errno, $errstr, 10); if (!$fp) { echo 'fail: fsockopen: '. $errono. ','. $errstr; exit; } fputs($fp, $request); $response = ""; while (!feof($fp)) { $response .= fgets($fp, 4096); } fclose($fp); } // POST ・ヌ。シ・ソ、ホトノイテ function add($key, $value) { if (strlen($this->post_str) > 0) { $this->post_str .= '&'; } $this->post_str .= $key. '='. $value; } } ?>
くらいかな?