FlexでSokectを使うときのに応答する

FlexはSocketが使えるわけですが、サーバーとの接続開始時に(正確にはTCP3ウェイハンドシェイクが完了したあとFlashPlayerから)

<policy-file-request/>\0

という文字列を送ってきます。
このとき、Socket.connect()で指定したポートもしくは、Socket.connect()で指定したホストのポート843もしくは、Security.loadPolicyFile()で指定したポートに要求が飛びます。
これは、FlashPlayerがドメイン間での接続許可をサーバ側に求めています。

まとめて書くとわかりにくいので、例を。

パターン1)
Socket.connect("hoge.com", 8888);
//hoge.comのポート843問い合わせ、応答がない場合ポート8888に問い合わせます。
//このときポート843で応答があった場合、コネクションが成立し、8888に問い合わせません。

パターン2)
Security.loadPolicyFile("xmlSocket://hoge.com:7777")
Socket.connect("hoge.com", 8888);
//hoge.comのポート7777に問い合わせ、応答がない場合はポート8888に問い合わせます。
//このときポート7777で応答があった場合、コネクションが成立し、8888に問い合わせません。

さらに接続先のポートが1024以上と以下で挙動が異なります。

パターン1)
接続先ポート1024以下から認証があった場合、すべてのポートに対してコネクションが張れます。

パターン2)
接続先ポート1024以上から認証があった場合、すべての1024番以上のポートに対してコネクションが張れます。

//これ以外にも一つのページに複数のSWFがあるときとか、一つのSWFから複数コネクションを張るなどいろいろテストしたいところ


これに対してサーバーは、

<cross-domain-policy><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>\0

と応答してあげることで、接続してきたSWFとコネクションが張ることができます。

このとき、サーバ側は応答メッセージを返したあと、一度コネクションを切断します。
するとコネクション切断を検知したFlashPlayerが再度接続してくることで、サーバとの通信が開始されます。
(一度切断する理由はわかりませんが、FlashPlayerの仕様みたいです。)



これについて、Flexにはドメイン間ロード許可としてcrossdomain.xmlを用いるのが一般的ですが、SocketおよびXMLSocketを用いるときはcrossdomain.xmlの内容にかかわらずサーバーの応答のみをみて、接続するかしないかを決めています。

というわけで、クライアントから要求が着たら応答するものをPHPで書いてみた。

<?php
echo "socket listen start\n";

//Listenするポート番号
$port = 8888;
$sock = socket_create_listen($port);

while(1)
{
	$clientsock = socket_accept($sock);
	while(1)
	{
		/*
		 * 接続確認
		 * クライアントから切断した時はclose
		 */
		if($buf = socket_read($clientsock, 1024))
		{
			if(strlen($buf) > 0)
			{
				/*
				 * Flex Connection start
				 * Flexに応答を返していったん接続をきる。
				 */
				if($buf == "<policy-file-request/>\0")
				{
					echo "flex comes\n";
					//応答
					$flex_auth = "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0";
					socket_write($clientsock, $flex_auth);
					socket_close($clientsock);
					$clientsock = socket_accept($sock);
				}
				socket_write($clientsock, $buf);
			}
		} else {
			break;
		}
	}
	socket_close($clientsock);
	echo "closed\n";
}
socket_close($sock);
?>

これで一通りつながります。
あとはサーバからsocket_write()をすると、Flex側でDataEvent.DATAが発生するので、事前に

addEventListener(DataEvent.DATA, dataHandler);

とすることでデータを受け取ることができます。