XMLSocketでechoクライアントを作る

とりあえずできた。IEでも動作。

Flashからconsole.logに出力できるのは便利だなー。

クライアント

echo_client.as
import flash.external.ExternalInterface;

class EchoClient {
  static function main() {
    var log = function(msg) {
      ExternalInterface.call('window.console.log', msg);
    }

    var socket = new XMLSocket();

    socket.onConnect = function (success) {
      log('onConnect(): ' + success);
    }

    socket.onData = function (src) {
      log('onData(): ' + src);
      ExternalInterface.call('recv_from_echod', src);
    }

    ExternalInterface.addCallback('connect_to_echod', null, function() {
      var connected = socket.connect(null, 10007);
      log('connect(): ' + connected);
    });

    ExternalInterface.addCallback('close_from_echod', null, function() {
      socket.close();
      log('close()');
    });

    ExternalInterface.addCallback('send_to_echod', null, function(msg) {
      socket.send(msg);
    });
  };
}

MTASCでコンパイル。

~$ mtasc -version 8 -swf echo_client.swf -main echo_client.as -header 0:0:0
echo_client.html
<html>
  <head>
    <script type="text/javascript">
      function $(id) {
        return document.getElementById(id);
      }

      function $M(movieName) {
        return (navigator.appName.indexOf("Microsoft") != -1) ? window[movieName] : document[movieName];
      }

      function recv_from_echod(msg) {
        alert(msg);
      }
    </script>
  </head>
  <body>
    <object id="myflash" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="0" height="0">
      <param NAME="movie" VALUE="echo_client.swf">
      <embed name="myflash" src="echo_client.swf" width="0" height="0"></embed>
    </object>
    <input id="send_text" type="text">
    <input type="button" value="send" onclick="$M('myflash').send_to_echod($('send_text').value);">
    <br>
    <input type="button" value="connect" onclick="$M('myflash').connect_to_echod();">
    <input type="button" value="close" onclick="$M('myflash').close_from_echod();">
  </body>
</html>

サーバ

require 'socket'

class TCPSocket
  def recv_from_flush
    buf = ''

    while c = self.getc
      c.nonzero? or break
      buf << c
    end

    return buf
  end
end

alive = true
trap(:INT) { alive = false }

TCPServer.open('localhost', 10007) {|sock|
  while alive
    select([sock], nil, nil, 0.5) or next
    Thread.fork(sock.accept) {|s|
      puts 'accepted.'
      while msg = s.recv_from_flush
        not msg.empty? or break
        p msg
        if /policy-file-request/ =~ msg
          # s.write(<ポリシーのXML>)とか書いていたような…
          # コピペミスかな?
          break
        else
          s.write("#{msg}\0")
        end
        s.flush
      end
      s.close
      puts 'closed.'
    }
  end
}