跳到主要內容

Android , Adobe AIR Socket

大家好,我是奶綠茶
今天來介紹一下 Adobe AIR ServerSocket
需求:
很多台電腦,在同一個區網,要能彼此溝通,同時 Android 平版也要能傳接值。
解:
本來想如果就只有單 flash 的話, 可以使用 P2P 區網連線就決解了,
但因為 Andriod 平版也要能支援, 所以就改成 Socket 來溝通。

那為什麼不用 Java 架 Socket Server 就好了,因為我是閃客(因為用 Java 做動畫會死人)
AIR 端,使用ServerSocket 類別。
在畫面上就只放所有連線的 Client 列表,一個發送訊息的文字和Button, 一個接收的文字
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                       xmlns:s="library://ns.adobe.com/flex/spark"
                       xmlns:mx="library://ns.adobe.com/flex/mx"
        creationComplete="createComplete(event);"
        close="appCloseHandler()">
 
 <fx:Declarations>
  <!-- Place non-visual elements (e.g., services, value objects) here -->
 </fx:Declarations>
 
 <fx:Script>
  <![CDATA[
  import flash.display.NativeWindow;
  import flash.events.Event;
  import flash.events.ProgressEvent;
  import flash.events.ServerSocketConnectEvent;
  import flash.net.ServerSocket;
  import flash.net.Socket;
  import flash.utils.ByteArray;
  import mx.collections.ArrayCollection;
  import mx.controls.Alert;
  import mx.events.FlexEvent;
  
  
  private var server :ServerSocket = new ServerSocket();
  
  [Bindable]
  private var serverActivity:Boolean = false;
  
  [Bindable]
  private var clientSockets:ArrayCollection = new ArrayCollection();
  
  //private var ipAddress  :String = "192.168.253.176";
  private var ipAddress  :String = "127.0.0.1";
  private var ipAddressPort :int = 9527;
  
  private function createComplete(e:FlexEvent):void {   
   
   try {
    server.bind(ipAddressPort, ipAddress);
    log( "bind:" + ipAddress+":"+ipAddressPort );
    server.addEventListener(ServerSocketConnectEvent.CONNECT , clientConnectedHandler);   
    server.listen();
    serverActivity = true;
   }catch (err:Error){
    log( err + "" );
    serverActivity = false;
    Alert.show(err.message);    
   }   
  }
  
  private function clientConnectedHandler(e:ServerSocketConnectEvent):void {
   //每當有新的 Client 連該進來, 就會觸發該函式。
   var clientSocket:Socket = e.socket;
   log( clientSocket.localAddress + ":" + clientSocket.localPort );
   clientSockets.addItem( clientSocket );
   clientSocket.addEventListener(Event.CLOSE , clientDisconnectedHandler);
   //偵聽當 Client 離線時。
   clientSocket.addEventListener(ProgressEvent.SOCKET_DATA, onClientSocketData );
   //偵聽 Client 發出的訊息
  }
  
  private function onClientSocketData(e:ProgressEvent):void {
   // 讀取 Client 發出的訊息
   var buffer:ByteArray = new ByteArray();
   var clientSocket:Socket = e.currentTarget as Socket;
            clientSocket.readBytes( buffer, 0, clientSocket.bytesAvailable );
            log( "Received: " + buffer.toString() );   
  }
  
  private function clientDisconnectedHandler(e:Event):void {
   // 當 Client 離線時。
   e.currentTarget.removeEventListener( e.type , arguments.callee );
   clientSockets.removeItemAt( clientSockets.getItemIndex(e.target));
  }
  private function log(o:Object):void {
   textArea.text += o +"\n";
  }
  
  private function writeDataToSockets(e:Event):void {
   var msg:String = textInput.text;
   if (msg == "") {
    return;
   }   
   trace( "ServerSocketMain.writeDataToSockets ");
   // 對所有的 Client 發出訊息。
   for each (var socket:Socket in clientSockets) {
    if (socket.connected) {     
     try {
      socket.writeUTF(msg);
      socket.flush();
     }catch (err:Error){
      log(err);
     }     
    }
   }
  }
  private function appCloseHandler():void {  
   server.close();
   server = null;   
  } 
  
  
  ]]>
 </fx:Script>
 <s:HGroup width="100%" height="100%" paddingLeft="5">
  <s:List width="200" height="100%" dataProvider="{clientSockets}" labelField="localAddress"></s:List>
  
  <s:VGroup width="100%" height="100%">
   <s:HGroup width="600">
    <s:TextInput id="textInput" width="200" text="server send info to all client" />
    <s:Button x="130" y="10" label="Send" 
     click="writeDataToSockets(event)" 
     enabled="{textInput.text.length>0}" visible="{clientSockets.length>0}" />
   </s:HGroup> 
   <s:Button label="clear" click="{textArea.text=''}" enabled="{serverActivity}"/>
   <s:TextArea id="textArea" width="200" height="100%" editable="false" />
  </s:VGroup>
 </s:HGroup> 
</s:WindowedApplication>

在用 flash 寫一個 Client 端測試:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/halo"
      creationComplete="createSocket(event)">
 <s:layout>
  <s:VerticalLayout />
 </s:layout>
 <fx:Script>
  <![CDATA[
   import flash.events.Event;
   import flash.events.ProgressEvent;
   import flash.net.Socket;
   import mx.events.FlexEvent;
          
   protected var socket:Socket;
   
   private var ipAddress  :String = "127.0.0.1";
   private var ipAddressPort :int = 9527;
   
   protected function createSocket(event:FlexEvent):void {    
    socket = new Socket();
    socket.addEventListener(Event.CONNECT,socketConnected);
    socket.addEventListener(ProgressEvent.SOCKET_DATA, socketData);      
    socket.connect( ipAddress, ipAddressPort );    
   }   
   protected function socketConnected(e:Event):void{
    log("client - socket connected");
   }   
   protected function socketData(e:ProgressEvent):void{
    trace("client - socket data");
    //trace(socket.readUTF());    
    log(socket.readUTF());    
   }   
   private function callServerClickHandler():void {
    try {
     socket.writeUTF("callServer");
     socket.flush();
    }catch (err:Error){
     log(err);
    }
    
   }
   private function log(o:Object):void {
    textArea.text += o + "\n";
   }
   
  ]]>
 </fx:Script>
 <s:Button label="call Server" click="callServerClickHandler()" />
 <s:TextArea id="textArea"></s:TextArea>
</s:Application>

Java/Android 端
使用 Socket 類別
因為程式碼落落長,
有需要的朋友就直接下載 Android 端的程式碼,在這就不貼出來了

AIR
Java/Android
轉載請註明出處

留言

奶綠您好
代理ARToolkit的擴增實境公司於12月3日舉辦手機版擴增實境ARToolkit for iOS一日通課程,請詳官網http://www.ar-truth.com/cover-page/news
※ 課程目標:
1.瞭解擴增實境 (AR) 市場規模及國際趨勢
2.讓從來沒用過ARToolkit 的人,從一開始的步驟開始教學,到可以運用在
iPhone上的AR,用iPhone偵測marker叫出動畫,完成一項實際案例。
奶綠您好 麻煩您張貼手機版擴增實境ARToolkit for iOS一日通課程,給同好朋友分享,謝謝您!
NL寫道…
想問一下 , flash 的 ServerSocket()跟
一般 C+ Server or java server
是做一樣的工作嗎 ? 還是...
效能會較差呢 ?
milkmidi寫道…
NL您好
因為我沒有壓力測試過 AIR 的 Server
所以不清楚效能的部份
Cain寫道…
老師你好!我把客戶端寫成Web版,跟這個AIR的Server連線,一開始連不起來(2048錯誤),後來我參考了這個文件(http://blog.pchome.net/article/2582.html) 自己在server作了一個843服務,等收到了字串後,隨即返回crossdomain的內容..不過試了很久(後來還嘗試用了Security.loadPolicyFile(),從別的port讀進去)結果也是一樣跳2048錯誤,請問老師有處理過這樣的問題嗎?
Cain寫道…
不好意思!我解決了XD 原來送出後843Port要關掉才能繼續下去..
吳子杰寫道…
老師您好 我把程式都放在package但我HTML的List data Provider 抓不到我的client Sockets 的值 請問該怎麼做?

這個網誌中的熱門文章

webpack2 入門實戰 1

大家好,我是奶綠茶
前端戰場不再只是寫寫 js / css , 各種框架、前處理工具百花齊放
身為前端工程師,不只要把程式寫完,還要寫好
老師說:選對好工具,事情就完成一半
如果你還在一隻 JS 打完全部程式,一隻 css 寫所有的 style
每次存檔還在手動 reload 網頁, 圖片壓 K 壓到不要不要的
透過奶綠伯的系列教學,讓你了解 webpack2 帶來的優勢
學會 webpack 可能不會加薪,但至少可以準時下班(誤)
1. 安裝 nodejs
請參考 gulp 安裝編

2. 安裝 global webpack , 筆者使用的是 2.2.1 版本
npm i webpack@2.2.1 -g
3. 在專案的根目錄放一隻 webpack.config.js
entry:你的主 js 進入點
output.filename:webpack 打包後的檔名
output.path:webpack 打包後的路徑
var path = require('path'); module.exports = { entry: './src/app.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } };
4. require , module.exports
現在前端都 module 化
可以每個獨立的功能都寫成單一的 js module
除了好管理,也方便讓團隊使用
寫一隻 module_exports_util.js
每隻經過 webpack 打包的 js , 都會是獨立的檔案
所以變數都是私有的, 外部成員都無法得到
在這個 module 裡,我們想開放二個函式
add , getName
所以在最後的 module.exports 指定
筆記加入 jsdoc , 為了方便在開發時,能夠有型別的提示

var name = "milkmidi"; /** * @param {number} num1 * @param {number} num2 * @return {number} */ function ad…

Android完全入門篇-01 安裝SDK與裝置USBDriver

大家好,我是奶綠茶
筆者以 Windows 系統來介紹安裝
1. 下載 Android SDK
http://developer.android.com/sdk/index.html
有分 32 位元和 64 位元的版本
為了教學方便,筆者將檔案放置在 D:\ 下
壓開後會有
eclipse資料夾:Eclipse程式碼編譯器
sdk:Android 開發用的 SDK
SDK Manager.exe:sdk管理用的軟體


2. 開啟手機的"開發人員選項"
部份手機該選項被隱藏起來了
要開啟的話,點選"關於手機"
接著連點"版本號碼"七次,就會重新開啟該功能
接著再開啟"USB偵錯"功能
接上你的 USB 線後
這樣你的電腦才能透過 USB 線來偵錯手機的資訊
3. 為裝置安裝 adb usb driver
因為各家廠牌的 Driver 都不同也不通用,所以需要自行 Google 找 Driver
可以用"XXX廠牌 型號 adb usb driver"關鍵字來找
例:HTC Newone adb usb driver
接著找到 我的電腦 / 內容


裝置管理員

會看到一個金嘆號未知的裝置, 按右鍵更新驅動程式軟體

選擇"瀏覽電腦上的驅動程式軟體"

完成後就會看到裝置啟動,並出現 XXX Android ADB Interface

4.測試是否連接成功
進入到第一步下載的 sdk 資料夾裡
D:\adt-bundle-windows-x86_64-20131030\sdk
然後在 platform-tools 資料夾上按住 Shift 鍵,然後再按滑鼠右鍵
選擇"在此處開啟命令視窗"
(此功能只有 Win7 之後的版本才支援, XP使用者就要自行輸入 dos 指令進入到資料夾)
輸入 adb devices
如果看到一串數字,並顯示 device 就表示連線成功
5.新增環境變數(選擇性設定)
為了方便的使用 adb 指令
可以為 windows 設定變數
開啟我的電腦 / 內容 / 左邊的"進階系統設定"
點選下方 環境變數

下方系統變數,找到 Path的選項,按下編輯

在變數值欄位的最後方加入
;D:\adt-b…

webpack2 入門實戰 3 scss,html,file-loader

大家好,我是奶綠茶
上一篇介紹了 webpack 的核心功能 loader
這篇再來補強各種常用的 loader
css-loader:解悉 css 檔
extract-loader:這個有點難翻,下面會介紹
file-loader:存成實體的檔案, 如圖片
html-loader:解悉 html 檔
sass-loader:解悉 scss 檔
url-loader:解悉圖片路徑
webpack.config.js
module.exports = { resolveLoader: { // 所有用到的 loader, -loader 可以不用打 moduleExtensions: [ "-loader" ], }, resolve: { // 在 require 檔案, 如果不想寫完整的路徑 // 可以加入這些目錄, 讓 webpack 自動尋找對的檔案 // 請注意我們加入了 src/img 路徑,後面會再介紹到 modules: [ path.resolve( 'src/html' ), path.resolve( 'src/img' ), path.resolve( 'src/css' ), path.resolve( 'src/js' ), path.resolve( "node_modules"), ], // 在 require 時可以不用打副檔名 extensions: [ ".js", ".scss" ] }, } 再來就是 loader 的介紹
scss
在這要做多組合的應用
先將 .scss 透過 scss-loader 轉換, 並產生 sourceMap 檔
再過 css-loader
最後再過 style-loader
{ test: /\.scss$/, // 多個 loader 組合, 可寫成一行,或…