Android udp 广播发送和接收

摘要:
2.注意,udp广播和udp广播监控需要绑定到同一端口。其他与IDE通风有关的问题,例如我的Android Studio,有时当你修改代码并将程序重新刻录到手机中时,它会使用缓存中的旧版本代码来刻录程序。。。

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

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

转载请注明出处:

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

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

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

代码逻辑:

  本机发送udp广播

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

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

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

具体ui操作:

Android udp 广播发送和接收第1张

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文件中同步。

Android udp 广播发送和接收第2张

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

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

免责声明:文章转载自《Android udp 广播发送和接收》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇初见Python&amp;lt;2&amp;gt;:列表和元组eclipse创建项目(步骤加图片)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android—TableLayout自定义表格

最近的一个项目中,需要用的表格,由于平时很少用到表格,所以,就准备到网上搜搜,发现可参考的很少,加上,自己也想多了解点TableLayout 布局,所欲就打算自己动手来实现自己需要的表格。先看看需求吧。 如图,上面这几个表格都差不多。主要区别: 1.列数不同 2.列的宽度不一定是均分的。 谈下思路: 从图我们可以看出,表头和表格可以分为两个表。...

数据储存——远程服务器存储——JSON

JSON 一.特点     1.JavaScript Object Notation     2.一种轻量级的数据交互格式 二.格式     1.[ ] 数组:[value1, value2, value3...]     2.{ } 对象:{key1:value1, key2:value2, key3:value3,...}       1-key:字符...

Android使用PopupMenu创建弹出式菜单

PopupMenu 代表弹出式菜单,它会在指定组件上弹出PopupMenu,在默认情况下PopupMenu会显示在该组件的下方或者上方。PopupMenu可增加多个菜单项,并可以为菜单项增加子菜单。 实现效果: 实现步骤: 步骤一: 创建主布局文件: <?xml version="1.0" encoding="utf-8"?> <Lin...

Android百度地图开发-第一篇:申请、搭建百度地图

一、前言 这是第一篇关于Android使用百度地图的学习记录,主要记录:   1.在百度地图开发者平台上申请API Key。   2.在自己的应用中加入百度地图的Android版SDK。   3.在自己的应用中显示一个地图。 二、在百度地图开发者平台上申请API Key 百度地图开发者平台地址:http://lbsyun.baidu.com/index....

Python——eventlet

eventlet语境下的“绿色线程”普通线程之间的区别:   1. 绿色线程几乎没有开销,不用像保留普通线程一样保留“绿色线程”,每一个网络连接对应至少一个“绿色线程”;   2. 绿色线程需要人为的设置使其互相让渡CPU控制权,而不是抢占。绿色线程既能够共享数据结构,又不需要显式的互斥控制,因为只有当一个绿色线程让出了控制权后其他的绿色线程才能访问彼此共...

[转载]Android系统开机画面的实现

 Android系统开机画面分为下面三个阶段: 1、开机图片:Android内核是基于标准内核的,对linux比较熟悉,特别是在开发板上移植过Linux系统的人就知道在内核引导过程中会显 示出一 个小企鹅的图片,这就是第一阶段的开机图片,相信大家知道怎么去修改它。Android1.5及其以上版本都取消了这个图片的显示,具体的看内核相关代码 就知道了; 2、...