読者です 読者をやめる 読者になる 読者になる

kkAyatakaのメモ帳。

誰かの役に立つかもしれない備忘録。

AIR.簡易Messengerを作る その2

まずはSearchボタン周りから作る。


node検出用メッセージの送信、待ち受け、返信の処理は、
DatagramSocketで試してた内容を、ほぼそのまま移植。
コメントの追加と、繰り返し使う値を定数宣言して運用。


ListはArrayCollectionにバインド。

...
private const nodes:ArrayCollection = new ArrayCollection( ["192.168.0.10"] );
...
<mx:List id="nodeList" width="100%" height="60%" dataProvider="{nodes}"/>

未だにこの書き方が正しいのか分かりませんが、
警告も出ないし、ちゃんと動くのでよかろーよ。


Linuxからbroadcastができないので、
nodesメンバにあらかじめIPアドレスを入れておくことにします。


Searchボタン押下処理で中身をクリアして・・・

private function searchBtn_clickLogic():void
{
	...
	nodes.removeAll();
	...
}


datagramSocketの受信ハンドラで、node検出用メッセージの返信なら、
データとしてIPアドレスを確保します。

private function datagramSocket_dataHandler(event:DatagramSocketDataEvent):void
{
	...
	// メッセージを確保
	var msg:String = event.data.readUTF();
	
	// broadcastメッセージか判定
	if( msg == MSG_SEARCH_NODE ) {
		...
	}
	else {
		// broadcastメッセージの返信なので、
		// 送信元のIPアドレスをnode一覧に追加する
		nodes.addItem( event.srcAddress );
	}
	...
}


これでsearchボタンの機能が完成。
broadcastメッセージが自分自身にも届くため、
リストに自分自身のIPアドレスも表示されますが、まあ、よしとしましょう。

その他調整

<mx:WindowedApplication ... width="450" height="400" ...>

Windowsで見たときサイズが大きすぎたので、指定。
モニターのドットピッチがかなり異なることを考慮してなかった。

簡易Messenger全ソース

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="vertical" horizontalAlign="left" showStatusBar="false" fontSize="20"
	width="450" height="400"
	initialize="initializeLogic()" close="closeLogic()">
	
	<!-- logic -->
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			
			//--------------------------------------------------------------------------------------
			// constants
			//--------------------------------------------------------------------------------------
			/** node検出のbroadcastに使うポート */
			static private const PORT_BROADCAST:int = 50000;
			
			/** node検出用にbroadcastするメッセージ */
			static private const MSG_SEARCH_NODE:String = "message search node";
			/** node検出メッセージに対して、返信するメッセージ */
			static private const MSG_NODE_RES:String = "message node res";
			
			//--------------------------------------------------------------------------------------
			// logics
			//--------------------------------------------------------------------------------------
			/** application initialize */
			private function initializeLogic():void
			{
				try {
					// broadcastの受信開始
					datagramSocket = new DatagramSocket();
					datagramSocket.addEventListener(DatagramSocketDataEvent.DATA, datagramSocket_dataHandler);
					datagramSocket.bind( PORT_BROADCAST );
					datagramSocket.receive();
				}
				catch( e:Error ) {
					trace( e.message );
				}
			}
			
			/** application close */
			private function closeLogic():void 
			{
				// リソース開放
				datagramSocket.close();
			}
			
			/** search button click */
			private function searchBtn_clickLogic():void
			{
				try {
					// node情報をクリアする
					nodes.removeAll();
					
					// node検出用メッセージをbroadcast
					var ba:ByteArray = new ByteArray();
					ba.writeUTF( MSG_SEARCH_NODE );
					datagramSocket.send(ba, 0, 0, "192.168.0.255", PORT_BROADCAST);
				}
				catch( e:Error ) {
					trace( e.message ); // Linuxはsendで例外 AIR 2.0 beta2
				}
			}
			
			/** send button click */
			private function sendBtn_clickLogic():void
			{
			}
			
			//--------------------------------------------------------------------------------------
			// handlers
			//--------------------------------------------------------------------------------------
			/** datagram socket data */
			private function datagramSocket_dataHandler(event:DatagramSocketDataEvent):void
			{
				try {
					// メッセージを確保
					var msg:String = event.data.readUTF();
					
					// broadcastメッセージか判定
					if( msg == MSG_SEARCH_NODE ) {
						// node検出用のbroadcastメッセージなので、返信する
						// 送信データ作成
						var ba:ByteArray = new ByteArray();
						ba.writeUTF( MSG_NODE_RES );
						// 送信
						event.target.send(ba, 0, 0, event.srcAddress, PORT_BROADCAST);
					}
					else {
						// broadcastメッセージの返信なので、
						// 送信元のIPアドレスをnode一覧に追加する
						nodes.addItem( event.srcAddress );
					}
				}
				catch( e:Error ) {
					trace( e.message );
				}
			}
			
			//--------------------------------------------------------------------------------------
			// private members
			//--------------------------------------------------------------------------------------
			/** broadcast用 */
			private var datagramSocket:DatagramSocket;
		
			/** ローカルネット内のPC */
			private const nodes:ArrayCollection = new ArrayCollection( ["192.168.0.10"] );
		]]>
	</mx:Script>
	
	<!-- components -->
	<mx:Button label="Search" width="140" click="searchBtn_clickLogic()"/>
	<mx:List id="nodeList" width="100%" height="60%" dataProvider="{nodes}"/>
	<mx:TextArea id="textArea" width="100%" height="40%"/>
	<mx:Button label="Send" width="100%"/>

</mx:WindowedApplication>