zoukankan      html  css  js  c++  java
  • Android udp 广播发送和接收

    最近在和同学开发一款app,作为课程大作业。其中,涉及到udp socket (多播) 的发送和接收、tcp socket 的发送和接收。作为一个Java的门外汉,在简单地看了一些理论地资料之后,实际编程中遇到了不少问题。然后,又在网上大搜这方面的博客,找来找去,其实大家写的东西基本都一样,因为规则已经订好了。网上的代码不全,又有一些错漏,让我走了很多弯路,无数次推倒代码重写,debug,终于调出了一个实际可运行的版本。 希望初学的童鞋看到我的这篇博客能少走一些弯路.

    -----------------------

    转载请注明出处:

    http://www.cnblogs.com/zhangzph/p/4475962.html

    -----------------------

    在给出代码之前,先简单介绍一下我的代码在做什么。 

    代码逻辑:

      本机发送udp广播

      本机开启线程,监听来自别的机器的udp广播,显示信息。 然后,对udp来源发送tcp连接

      接收来自别的机器的tcp连接,并显示信息

      (这里的udp广播,我使用udp多播代替了,多播具有广播的所有优点,而且有更少的缺点,实现上也比较简单,这里就不再过多地介绍了)

    具体ui操作:

    start 按钮用来启动udp 多播,stop按钮停止发送 (实际上,由于start 按钮按下之后只发送一次udp多播,stop按钮只是用于setEnabled操作)下面有两个TextView,内容为send的TextView 显示--本机发送 tcp socket 的信息; 内容为receive的TextView 显示--本机接收来自别的机器的udp socket 和 tcp socket 的信息. 

      

    几个需要注意的地方:

    1. Android Manifest 权限设置、sdk版本信息:

      本文所涉及到的这些功能需要获取 Android 的一些权限,下面是我的权限和版本信息

    <uses-sdk
            android:minSdkVersion="15"
            android:targetSdkVersion="21" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
        <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
        <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    

    上面 条目 uses-sdk中的信息,需要在build.gradle文件中同步。

    2. 注意udp广播,和udp广播监听需要绑定同一个端口

    3. 其他的有关IDE抽风的问题,比如我的Android Studio,有时候你修改了代码,重新把程序烧进手机的时候,它竟然会用缓存中代码的老版本来烧程序。。。 还有,有时候project加载太慢,程序崩溃之后,logcat好长时间都不出错误信息,严重影响debug。

    4. 建议使用android sdk版本比较新的手机进行测试。 我测试的时候,用一部4.4和5.1的成功了。混合另外一部4.0.x的则有时候不太灵通。

    github上的项目链接:

     https://github.com/zhangpzh/Anjay

    主要代码:

    xml 源码:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MyActivity">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_horizontal"
            >
            <Button
                android:id="@+id/start"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="start"
                />
            <Button
                android:id="@+id/stop"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="150dp"
                android:text="stop"
                />
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_horizontal"
            >
            <TextView
                android:id="@+id/send_information"
                android:layout_marginTop="50dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="send"
                android:layout_marginRight="110dp"
                />
            <TextView
                android:id="@+id/receive_information"
                android:layout_marginTop="50dp"
                android:text="receive"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />
        </LinearLayout>
    </LinearLayout>

    Java 源码:

    (github 上面的代码已经把各个通信内部类给模块化了,不再像下面这样,全都定义在一个Activity里。但是为了集中展示app的功能,下面仍使用一个文件显示)

    package com.example.user.anjay;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    import com.example.user.anjay.R;
    
    import org.apache.http.conn.util.InetAddressUtils;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.DatagramPacket;
    import java.net.InetAddress;
    import java.net.MulticastSocket;
    import java.net.NetworkInterface;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.Enumeration;
    
    
    public class MyActivity extends Activity {
    
        private static String LOG_TAG = "WifiMulticastActivity";
    
        Button startBroadCast;
        Button stopBroadCast;
    
        TextView send_label;
        TextView receive_label;
    
        /* 用于 udpReceiveAndTcpSend 的3个变量 */
        Socket socket = null;
        MulticastSocket ms = null;
        DatagramPacket dp;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_my);
    
            startBroadCast = (Button) findViewById(R.id.start);
            stopBroadCast = (Button) findViewById(R.id.stop);
    
            send_label = (TextView) findViewById(R.id.send_information);
            receive_label = (TextView) findViewById(R.id.receive_information);
    
            send_label.append("
    
    ");
            receive_label.append("
    
    ");
    
            startBroadCast.setOnClickListener(listener);
            stopBroadCast.setOnClickListener(listener);
    
            /* 开一个线程接收tcp 连接*/
            new tcpReceive().start();
    
            /* 开一个线程 接收udp多播 并 发送tcp 连接*/
            new udpReceiveAndtcpSend().start();
        }
    
        private View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v == startBroadCast ) {
                    startBroadCast.setEnabled(false);
                    stopBroadCast.setEnabled(true);
    
                    /* 新开一个线程 发送 udp 多播 */
                    new udpBroadCast("hi ~!").start();
                }
                else {
                    startBroadCast.setEnabled(true);
                    stopBroadCast.setEnabled(false);
                }
            }
        };
    
        /* 发送udp多播 */
        private  class udpBroadCast extends Thread {
            MulticastSocket sender = null;
            DatagramPacket dj = null;
            InetAddress group = null;
    
            byte[] data = new byte[1024];
    
            public udpBroadCast(String dataString) {
                data = dataString.getBytes();
            }
    
            @Override
            public void run() {
                try {
                    sender = new MulticastSocket();
                    group = InetAddress.getByName("224.0.0.1");
                    dj = new DatagramPacket(data,data.length,group,6789);
                    sender.send(dj);
                    sender.close();
                } catch(IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /*接收udp多播 并 发送tcp 连接*/
        private class udpReceiveAndtcpSend extends  Thread {
            @Override
            public void run() {
                byte[] data = new byte[1024];
                try {
                    InetAddress groupAddress = InetAddress.getByName("224.0.0.1");
                    ms = new MulticastSocket(6789);
                    ms.joinGroup(groupAddress);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                while (true) {
                    try {
                        dp = new DatagramPacket(data, data.length);
                        if (ms != null)
                           ms.receive(dp);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
                    if (dp.getAddress() != null) {
                        final String quest_ip = dp.getAddress().toString();
    
                        /* 若udp包的ip地址 是 本机的ip地址的话,丢掉这个包(不处理)*/
    
                        //String host_ip = getLocalIPAddress();
    
                        String host_ip = getLocalHostIp();
    
                        System.out.println("host_ip:  --------------------  " + host_ip);
                        System.out.println("quest_ip: --------------------  " + quest_ip.substring(1));
    
                        if( (!host_ip.equals(""))  && host_ip.equals(quest_ip.substring(1)) ) {
                            continue;
                        }
    
                        final String codeString = new String(data, 0, dp.getLength());
    
                        receive_label.post(new Runnable() {
                            @Override
                            public void run() {
                                receive_label.append("收到来自: 
    " + quest_ip.substring(1) + "
    " +"的udp请求
    ");
                                receive_label.append("请求内容: " + codeString + "
    
    ");
                            }
                        });
                        try {
                            final String target_ip = dp.getAddress().toString().substring(1);
                            send_label.post(new Runnable() {
                                @Override
                                public void run() {
                                    send_label.append("发送tcp请求到: 
    " + target_ip + "
    ");
                                }
                            });
                            socket = new Socket(target_ip, 8080);
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
    
                            try {
                                if (socket != null)
                                    socket.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    
    
    
        /* 接收tcp连接 */
        private class tcpReceive extends  Thread {
            ServerSocket serverSocket;
            Socket socket;
            BufferedReader in;
            String source_address;
    
            @Override
            public void run() {
                while(true) {
                    serverSocket = null;
                    socket = null;
                    in = null;
                    try {
                        Log.i("Tcp Receive"," new ServerSocket ++++++++++");
                        serverSocket = new ServerSocket(8080);
    
                        socket = serverSocket.accept();
                        Log.i("Tcp Receive"," get socket ++++++++++++++++");
    
                        if(socket != null) {
                            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                            StringBuilder sb = new StringBuilder();
                            sb.append(socket.getInetAddress().getHostAddress());
    
                            String line = null;
                            while ((line = in.readLine()) != null ) {
                                sb.append(line);
                            }
    
                            source_address = sb.toString().trim();
                            receive_label.post(new Runnable() {
                                @Override
                                public void run() {
                                    receive_label.append("收到来自: "+"
    " +source_address+"
    "+"的tcp请求
    
    ");
                                }
                            });
                        }
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    } finally {
                        try {
                            if (in != null)
                                in.close();
                            if (socket != null)
                                socket.close();
                            if (serverSocket != null)
                                serverSocket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        public String getLocalHostIp() {
            String ipaddress = "";
            try {
                Enumeration<NetworkInterface> en = NetworkInterface
                        .getNetworkInterfaces();
                // 遍历所用的网络接口
                while (en.hasMoreElements()) {
                    NetworkInterface nif = en.nextElement();// 得到每一个网络接口绑定的所有ip
                    Enumeration<InetAddress> inet = nif.getInetAddresses();
                    // 遍历每一个接口绑定的所有ip
                    while (inet.hasMoreElements()) {
                        InetAddress ip = inet.nextElement();
                        if (!ip.isLoopbackAddress()
                                && InetAddressUtils.isIPv4Address(ip
                                .getHostAddress())) {
                            return ip.getHostAddress();
                        }
                    }
                }
            }
            catch(SocketException e)
            {
                    Log.e("feige", "获取本地ip地址失败");
                    e.printStackTrace();
            }
            return ipaddress;
        }
    
        private 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()) {
                            return inetAddress.getHostAddress().toString();
                        }
                    }
                }
            } catch (SocketException ex) {
                Log.e(LOG_TAG, ex.toString());
            }
            return null;
        }
    
        // 按下返回键时,关闭 多播socket ms
        @Override
        public void onBackPressed() {
            ms.close();
            super.onBackPressed();
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.my, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }
    

    如果有错漏的地方,还请批评指正。毕竟是初学者,不出错,不疏忽是不可能的。

  • 相关阅读:
    hdu1421 搬寝室(dp)
    HDU 2577(DP)
    扩展欧几里德算法
    unique函数的作用
    区间更新 zoj3911
    set的应用
    vue 事件处理器
    vue Class与style绑定
    vue的计算属性
    sass入门
  • 原文地址:https://www.cnblogs.com/zhangzph/p/4475962.html
Copyright © 2011-2022 走看看