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中的信息,需要在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的功能,下面仍使用一个文件显示)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
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("\n\n");
        receive_label.append("\n\n");
 
        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("收到来自: \n" + quest_ip.substring(1) + "\n" +"的udp请求\n");
                            receive_label.append("请求内容: " + codeString + "\n\n");
                        }
                    });
                    try {
                        final String target_ip = dp.getAddress().toString().substring(1);
                        send_label.post(new Runnable() {
                            @Override
                            public void run() {
                                send_label.append("发送tcp请求到: \n" + target_ip + "\n");
                            }
                        });
                        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("收到来自: "+"\n" +source_address+"\n"+"的tcp请求\n\n");
                            }
                        });
                    }
                } 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);
    }
}

 

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

posted @   the_Gaven  阅读(24204)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示