1. 程式人生 > >Android之UDP協議通訊

Android之UDP協議通訊

最近在做的專案中用到了UDP協議來通訊,整理了一下,可以與PC端網路助手之間進行測試。下面將主要功能程式碼寫在下面供搭建參考:
UDPSocketClientManage

public class UDPSocketClientManage {

    // 伺服器IP

    private static String SERVER_IP = "192.168.1.68";

    // 伺服器埠

    private static int LOCAL_PORT_AUDIO = 10000;

    // 接收資料包

    private DatagramPacket Packet_Receive;

    // 埠
private DatagramSocket msocketClient; NetworkState mLastNetworkState = NetworkState.NETWORK_STATE_NULL; SocketConnectListener mConnectListener = null; // 設定網路連線引數 public void setNetworkParameter(String strIP, int nPort) { SERVER_IP = strIP; LOCAL_PORT_AUDIO = nPort; } // 註冊接收連線狀態和資料的回撥函式
public void RegSocketConnectListener(SocketConnectListener listener) { mConnectListener = listener; } /** * 啟動連線伺服器 */ public void Connect() { // 正在開始連線 mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_ING; try { // 埠
msocketClient = new DatagramSocket(LOCAL_PORT_AUDIO); // 接收資料快取 byte[] Buffer_Receive = new byte[1024]; // 接收包 Packet_Receive = new DatagramPacket(Buffer_Receive, 1024); mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_SUCCEED; } catch (IOException e) { mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_FAILLD; Log.e("Show", e.toString()); e.printStackTrace(); } catch (Exception e) { mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_FAILLD; Log.e("Show", e.toString()); e.printStackTrace(); } // 向回調發資料 if (null != mConnectListener) { mConnectListener.OnConnectStatusCallBack(mLastNetworkState); } if (msocketClient != null) { new Thread(reRunnable).start(); } } Runnable reRunnable = new Runnable() { @SuppressLint("NewApi") @Override public void run() { while (true) { try { // 接收資料 if (Packet_Receive != null) { msocketClient.receive(Packet_Receive); // 判斷資料是否合法 InetSocketAddress address = (InetSocketAddress) Packet_Receive.getSocketAddress(); // 判斷是否是排程伺服器的ip if (!address.getHostName().equals(SERVER_IP)) { continue; } // 判斷是否是排程伺服器的埠 if (address.getPort() != LOCAL_PORT_AUDIO) { continue; } int length = Packet_Receive.getLength(); if (length > 0) mConnectListener.OnReceiverCallBack(length, Packet_Receive.getData()); } } catch (IOException e) { e.printStackTrace(); Log.e("Show", e.toString()); } } } }; /** * 斷開連線 */ public void Close() { if (msocketClient != null) { msocketClient = null; mLastNetworkState = NetworkState.NETWORK_STATE_DISCONNECT_SUCCEED; mConnectListener.OnConnectStatusCallBack(mLastNetworkState); } } /** * @param data :需要傳送的資料 * @param len :資料位元組資料 * @brief 傳送資料 */ public void send(byte[] data, int len) { Thread_Send thread_send = new Thread_Send(data, len); new Thread(thread_send).start(); } /** * @brief 傳送執行緒 */ private class Thread_Send implements Runnable { // 傳送資料快取 private byte[] Buffer_Send = new byte[1024]; // 傳送資料包 private DatagramPacket Packet_Send; /** * @param data :需要傳送的資料 * @param len :資料位元組資料 * @brief 建構函式 */ public Thread_Send(byte[] data, int len) { // 傳送包 Packet_Send = new DatagramPacket(Buffer_Send, 1024); Packet_Send.setData(data); Packet_Send.setLength(len); } @Override public void run() { try { Packet_Send.setPort(LOCAL_PORT_AUDIO); Packet_Send.setAddress(InetAddress.getByName(SERVER_IP)); if (msocketClient != null) { msocketClient.send(Packet_Send); mLastNetworkState = NetworkState.NETWORK_STATE_TXD; mConnectListener.OnConnectStatusCallBack(mLastNetworkState); } else { mLastNetworkState = NetworkState.NETWORK_STATE_NULL; mConnectListener.OnConnectStatusCallBack(mLastNetworkState); } } catch (UnknownHostException e) { e.printStackTrace(); mLastNetworkState = NetworkState.NETWORK_STATE_NULL; mConnectListener.OnConnectStatusCallBack(mLastNetworkState); } catch (IOException e) { e.printStackTrace(); mLastNetworkState = NetworkState.NETWORK_STATE_NULL; mConnectListener.OnConnectStatusCallBack(mLastNetworkState); } } } // 獲取最後的網路狀態 public NetworkState getLastNetworkState() { return mLastNetworkState; } @SuppressLint("LongLogTag") public static String getLocalIpAddress() { try { for (Enumeration<NetworkInterface> en = NetworkInterface .getNetworkInterfaces(); en.hasMoreElements(); ) { NetworkInterface intf = en.nextElement(); for (Enumeration<InetAddress> enumIpAddr = intf .getInetAddresses(); enumIpAddr.hasMoreElements(); ) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) { return inetAddress.getHostAddress().toString(); } }

這裡寫程式碼片


        } catch (SocketException ex) {

            Log.e("WifiPreference IpAddress", ex.toString());

        }

        return null;

    }

}

介面SocketConnectListener

public abstract class SocketConnectListener {
    // 網路狀態回撥
    public abstract void OnConnectStatusCallBack(NetworkState networkState);

    // 接收資料回撥
    public abstract void OnReceiverCallBack(int nLength, byte[] data);

}

網路狀態列舉類NetworkState

//網路狀態列舉類
public enum NetworkState {
    NETWORK_STATE_NULL, // 無狀態
    NETWORK_STATE_CONNECT_SUCCEED, // 網路連線成功
    NETWORK_STATE_DISCONNECT_SUCCEED, // 網路斷開成功(自身斷開)
    NETWORK_STATE_SERVER_DISCONNECT, // 網路被伺服器斷開
    NETWORK_STATE_CONNECT_FAILLD, // 連線伺服器失敗,IP/埠不正常
    NETWORK_STATE_CONNECT_ING, // 正在連線過程中...
    NETWORK_STATE_RXD, // 接收資料
    NETWORK_STATE_TXD; // 傳送資料
}

主頁面連線使用類MainActivity

public class MainActivity extends ActionBarActivity implements View.OnClickListener {
    public static UDPSocketClientManage socketClientManage = null;
//    private String mstrDataString = "";
    private byte[] mstrDataString;
    private TextView textViewRecrive;
    public static byte[] bytes1_up = {(byte) 0xfa,(byte)0x01,(byte)0x05,(byte)0x01};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.button1).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
        findViewById(R.id.button3).setOnClickListener(this);
        TextView loTextView = (TextView) findViewById(R.id.textViewLoca);

        //手機端的連線路由之後IP地址,網路除錯助手向目標主機發送的IP地址就是這裡獲取出來的
        String strLoString = UDPSocketClientManage.getLocalIpAddress();
        if (strLoString != null) {
            loTextView.setText(strLoString);
        }
        textViewRecrive = (TextView) findViewById(R.id.textViewRecrive);
        socketClientManage = new UDPSocketClientManage();
        socketClientManage.RegSocketConnectListener(new SocketConnectListener() {

            @Override
            public void OnReceiverCallBack(int nLength, byte[] data) {
//                mstrDataString = new String(data);
                mstrDataString = data;
                mHandler.sendEmptyMessage(1);
            }

            @Override
            public void OnConnectStatusCallBack(NetworkState networkState) {
                switch (networkState) {
                    case NETWORK_STATE_CONNECT_SUCCEED:
                        mHandler.sendEmptyMessage(0);
                        break;
                    default:
                        break;
                }
            }
        });
    }

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0: // 接受到訊息之後,對UI控制元件進行修改
                    Toast.makeText(MainActivity.this, "連線成功", Toast.LENGTH_SHORT).show();
                    break;
                case 1: // 接受到訊息之後,對UI控制元件進行修改
//                    textViewRecrive.append(mstrDataString);
//                    textViewRecrive.setText(bytesToHexString(mstrDataString.getBytes()));
//                    Toast.makeText(MainActivity.this, mstrDataString, Toast.LENGTH_SHORT).show();
                    //下面是以16進位制方式來接收
                    String str1 = Integer.toHexString(mstrDataString [0]& 0xFF);
                    String str2 = Integer.toHexString(mstrDataString [1]& 0xFF);
                    String str3 = Integer.toHexString(mstrDataString [2]& 0xFF);
                    String str4 = Integer.toHexString(mstrDataString [3]& 0xFF);
                    if (str1.length() == 1) {
                        str1='0' + str1;
                    }
                    if (str2.length() == 1) {
                        str2='0' + str2;
                    }
                    if (str3.length() == 1) {
                        str3='0' + str3;
                    }
                    if (str4.length() == 1) {
                        str4='0' + str4;
                    }
                    textViewRecrive.setText(str1+" "+str2+" "+str3+" "+str4);
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button1:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        socketClientManage.Connect();
                    }
                }).start();
                break;
            case R.id.button2:
                EditText ipEditText = (EditText) findViewById(R.id.editText1);
                EditText porText = (EditText) findViewById(R.id.editText2);
                String ipString = ipEditText.getText().toString().trim();
                String portString = porText.getText().toString().trim();
                socketClientManage.setNetworkParameter(ipString, portString != null ? Integer.parseInt(portString) : 0);
                Toast.makeText(MainActivity.this, "設定成功", Toast.LENGTH_SHORT).show();
                break;
            case R.id.button3:
               socketClientManage.send(bytes1_up, bytes1_up.length);
                break;
            default:
                break;
        }
    }
}

佈局.xml檔案

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="本地IP地址:" />

        <TextView
            android:id="@+id/textViewLoca"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

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

            <requestFocus />
        </EditText>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="PC端的IP地址(也就是傳送資料伺服器地址):" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="PC端的IP埠(也就是傳送資料伺服器埠):" />

        <EditText
            android:id="@+id/editText2"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:inputType="number" >

            <requestFocus />
        </EditText>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="傳送給PC端的資料" />

        <EditText
            android:id="@+id/editText3"
            android:layout_width="match_parent"
            android:layout_height="40dp" >

            <requestFocus />
        </EditText>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:text="確定" />

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:text="連線" />

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="傳送" />
    </LinearLayout>

    <TextView
        android:id="@+id/textViewRecrive"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="接收到的資料:" />

</LinearLayout>

最後別忘了在AndroidManifest.xml裡新增許可權

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

以上這些就是全部程式碼,有不足指出還請大家指出
下面為大家附上原始碼