Android Socket UDP通訊

在Android SDK撰寫Socket UDP,讓手機與各種裝置通訊摟!

在網路上搜尋Android的UDP通訊,看到很多文章都是失敗收場,甚至有些文章直接寫Android不支援UDP通訊協定,不死心的我決定要再來好好研究,果然皇天不付有心人,在零碎的資料整合後終於完成了Android的UDP程式了,以下就由我一步一步教大家怎麼做吧!

 

首先,必須要先釐清一個事情,不論在Windows的.Net平台或是Android SDK中,一個軟體在執行時就會產生一個程序(大陸叫進程,Process),一個程序中可以擁有多個執行緒(大陸叫線程,Thread),在程式的撰寫中,MAIN函數會在主執行緒中運作,連通使用者介面(UI)也被賦予在主執行緒中,然而,在寫通訊程式的時候會利用多執行緒的方式來撰寫,原因是主執行緒的工作是負責MAIN以及UI的運作,讓副執行緒運作一個不間斷且持續運作的迴圈,以便監聽通訊的工作,所以在這個範例中,我們會使用到Android的多執行緒寫作技巧。

 

在Android的多執行緒寫作技巧中,必須搭配其他技術才得以讓副執行緒去變更由主執行緒負責的UI,這個技術就是Handler,不過在本篇中我們專注在UDP通訊的部分,其他如Thread以及Handler將會另外新增篇幅來向大家說明,接著就進入主題吧!

 

首先拉一個簡單的介面,由EditText、Button、TextView組成,如下圖:

image

 

【main.xml】

 


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="SEND" android:onClick="bt1_OnClick"/>

    <TextView
        android:id="@+id/TextView01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.33"
        android:text="@string/hello" />

</LinearLayout>

 

【AndroidManifest.xml】

在這個XML檔案中增加新的網路設定,以便讓模擬器可以使用正常的網路通訊功能,如下所示:


<uses-permission android:name="android.permission.INTERNET"/>

 

【AndroidSample_UdpActivity.java】


package peter.crispkid.namespace;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicBoolean;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Time;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class AndroidSample_UdpActivity extends Activity {	
	TextView tv1;
	Button bt1;
	EditText et1;
	Time t;
	private static final int UDP_SERVER_PORT = 11111;
    
	Handler handler=new Handler() {
        @Override
        public void handleMessage(Message msg) {  
        	super.handleMessage(msg);
        	String msgString = (String)msg.obj;      
        	t.setToNow();
        	tv1.setText(String.valueOf(t.hour)+":"+
    				String.valueOf(t.minute)+":"+
    				String.valueOf(t.second)+"=>"+msgString+"\n"+tv1.getText().toString());
        }
    };
    
    AtomicBoolean isRunning=new AtomicBoolean(false);
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tv1=(TextView) findViewById(R.id.TextView01);
        bt1=(Button) findViewById(R.id.button1);
        et1=(EditText) findViewById(R.id.editText1);
        t=new Time();
    }
    
    public void bt1_OnClick(View view)
    {    	  
    	try {
    		String sendData = et1.getText().toString();
			InetAddress serverAddr = InetAddress.getByName("192.168.1.6");
			DatagramPacket dp;
			dp = new DatagramPacket(sendData.getBytes(), sendData.length(), serverAddr, UDP_SERVER_PORT);
			try {
				ds.send(dp);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    DatagramSocket ds = null;
    public void onStart() {
        super.onStart();
        tv1.setText("START...");
        
        Thread background=new Thread(new Runnable() {
            public void run() {
                try {
                	String data;
                	byte[] recevieData = new byte[1024];
                	DatagramPacket dp = new DatagramPacket(recevieData, recevieData.length);
                	
            		ds = new DatagramSocket(UDP_SERVER_PORT);
            		
                    for (;isRunning.get();) {
                        Thread.sleep(100);
                        ds.receive(dp);
                        data = new String(recevieData, 0, dp.getLength());
                        handler.sendMessage(handler.obtainMessage(1,data));
                    }
                }
                catch (Throwable t) {
                    // just end the background thread
                }
            }
        });

        isRunning.set(true);
        background.start();
    }

    public void onStop() {
        super.onStop();
        isRunning.set(false);
    }
}

副執行緒負責維持通訊監聽的功能,在Android SDK中的規定,副執行緒若要更改UI的內容,必須使用Handler的Message的技巧來與UI做溝通。

 

當我們將上述程式都撰寫完畢後,即可開始執行Debug,當模擬器開始運作並載入APK後,在HOST端開啟命令提示字元,使用Telnet登入到Android模擬器內,並鍵入相關命令,如下圖:

image

 

該命令的結構是=>redir add <tup/udp>:port:port,這段命令代表的是將Host端的Port轉送到Android端的Port,否則在模擬器內的UDP Server將無法收到外部傳進來的通訊資料。

 

以上就是今天的教學了唷,若有細節不懂得,請留言詢問唷,或請跟我說哪邊需要更精進唷^^

 

PeterDotNetAndroidUDP12082601.zip