天天看點

Android之UDP協定通訊

最近在做的項目中用到了UDP協定來通訊,整理了一下,可以與PC端網絡助手之間進行測試。下面将主要功能代碼寫在下面供搭建參考:

UDPSocketClientManage

public class UDPSocketClientManage {

    // 伺服器IP

    private static String SERVER_IP = "192.168.1.68";

    // 伺服器端口

    private static int LOCAL_PORT_AUDIO = ;

    // 接收資料包

    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[];

            // 接收包

            Packet_Receive = new DatagramPacket(Buffer_Receive, );



            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 > )

                            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[];

        // 發送資料包

        private DatagramPacket Packet_Send;



        /**

         * @param data :需要發送的資料

         * @param len  :資料位元組資料

         * @brief 構造函數

         */

        public Thread_Send(byte[] data, int len) {

            // 發送包

            Packet_Send = new DatagramPacket(Buffer_Send, );

            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) ,(byte),(byte),(byte)};
    @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();
            }

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

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

以上這些就是全部代碼,有不足指出還請大家指出

下面為大家附上源碼